记一次Docker中Redis连接暴增的问题排查
周六生产服务器出现redis服务器不可用状态 , 错误信息为:
状态不可用 , 等待后台检查程序恢复方可使用 。 Unexpectedendofstream;expectedtype'Status'
如下图所示 , 下图6300就是我们redis服务器运行的端口 。

文章图片
头一次碰到此类问题 , 心想难道是redis挂掉了 , 随即通过telnetip+端口 。 发现运行正常 , 然后就想着进入redis看下目前连接情况 。 一看发现竟然高达1903条这么多 。

文章图片
然后想着应该是代码创建redis连接过多导致的 , 查看代码 。

文章图片
发现redis创建只有这一个地方有 , 这里也是服务注册时才执行 。 也就是应用程序启动时才被执行一次 。 然后整个项目查找 , 没有其他地方再有调用redis初始化 。
心有不甘 , 难道是每次在redis读写数据时都会创建连接吗?会和读写频繁有关系吗?总感觉不会啊 , 随即创建测试代码进行测试一番 。
在本地搭建了一个redis环境 , 测试之前先看看接数多少 , 目前看只有1个 , 也就是目前的cmd连接客户端 , 这个属于正常的了 。

文章图片
开始测试 , 运行程序 。 代码是创建一个连接对象 , 并一共测试1000次写 , 和1000次读 。

文章图片
不管我怎么测试连接都是6个 , 那么也就是说我们程序最多创建了5个连接 , 当然主要有线程池在里面 。

文章图片
所以基本的存储读取这块代码肯定是没问题 。
但代码这块也没算完全放弃排查 , 因为生产服务器通过docker运行着大约6个应用程序 。 都是连接的同一个redis,会不会是其他应用程序导致的?
【记一次Docker中Redis连接暴增的问题排查】然后就想直接通过redis连接列表里的中随便一个端口来查询对应的进程信息就可以知道是哪些应用程序了 。
Linux中通过查询网络端口号显示进程信息 。
netstat-atunlp|grep60852
首先看这端口对应的IP , 比如这里第一个是172.17.0.1 。 熟悉docker的同学应该知道这个ip是docker网关IP 。 我们容器中的程序都是通过这个网关IP来和我们宿主主机来通讯的 。 我们通过ifconfig就能发现docker这个网关IP , 第二个172.17.0.3:6379这个一看就是redis的容器IP ,
这样一看确实无法找到具体对应哪个容器中的程序和我们建立连接的 。
有一个最笨的办法就是挨个进入容器里面 。 即dockerexec–ittest/bin/bash然后查看当前容器的网络连接情况 。 这样非常麻烦 , 并且需要安装很多组件才能执行一系列命令 。
另外一个办法lsof命令,如果没有则需要安装 。 我们可以通过进程去找所有网络连接情况 。
比如我们刚发现我们的进程主要是docker , 他的pid是582251 。
lsof-i|grep582251或者lsof-i-p582251
结果如下图 , 右边其实出现了具体IP , 这个IP就是docker容器具体的IP地址 。

文章图片
现在知道所有IP和端口了 , 我们将命令执行结果下载下来 。
首先找到自己每个容器对应的IP 。
dockerinspectname|grepIPAddress//name容器名称或者id

文章图片
找到每个ip后然后根据刚下载的所有网络连接信息进行统计 , 看哪个IP连接最多 , 最多的一个肯定有问题 。

文章图片
然后我就找到这个IP对应的容器部署的程序 , 然后看redis配置 。 发现线程池设为200 。

文章图片
另外我通过github,发现CSRedisCore还有个预热机制 , 也就是preheat , 他默认值就是5个预热连接 。

文章图片
我们线程池设置的是200加上本身有个预热机制5个连接 , 我不知道是不是会创建200*5=1000个 。 这个有时间再好好研究下源代码 , 目前只是猜测 。
我现在已经将redis修改为poolsize=5,preheat=false 。 线程池5个 , 并且关闭预热机制 。
修改我们连接配置 , 并重启应用服务器和redis服务器(为了彻底清除已建立的连接)后发现连接数有减少 , 但没有很多 。 后来查询发现 , 是redis的idle空闲时长太长 , 导致连接池维持太多连接 , 没有被释放 。

文章图片
我们设置下超时为30s
执行CONFIGSETtimeout30(单位是秒 , 此种方式只是临时修改 , 针对当前运行有效 。 长效记得修改redis配置文件)
然后再看下连接数多少 , 这样一下子就减少了很多 。

文章图片
总结:
1、redis连接暴增 , 首先从自身应用程序出发去寻找问题 , 比如我这边发现的连接池设置过大 , 加上默认的预热机制等 。 还有尽可能的看代码层面在创建连接是否会被多次触发 , 如果有就必须要改正 。 现在都是通过注入的方式创建实例 , 要看该地方是存在被多次调用 。
2、修改redis服务器配置 , 比如连接空闲超时时间 。 包括也可也看下最大连接数多少 , 默认值 。
作者:Cfan1236
推荐阅读
- 粤游记|旅游就该诗酒趁年华,带你一起到东京,我们玩点不一样的!
- 星车记|买车内饰也要好好斟酌,汽车座椅3个要点,不注意开久就后悔了
- 星车记|买车后如何正确调节座椅?
- 星车记|新能源车上市这么久,为啥很多人不喜欢?买过的车主说出实话
- 星车记|高速行车5大禁忌,必须要记牢,请花30秒通读一遍
- 星车记|喜提凯迪拉克CT6,外观不输劳斯莱斯宾利
- 星车记|9万买了一辆宝马5系,本以为自己捡到宝,拆开底盘一看维修工懵了
- 有着“蛇蝎心肠”4大生肖,“揣奸把猾”段位高,遇见记得躲着走
- 星车记|超标电动车遇检查怎么办?只要有了这个东西,交警也只能放你走
- 星车记|汽车新政策,车主终于不用担心这个问题了,快去排队检车
