去年圣诞节当天,忽然收到一个我经手过的项目的告警邮件,错误消息显示“Redis::CommandError: ERR max number of clients reached”。redis
什么状况?难道这个项目翻车了?第一反应是这台服务器运行着自建的 Redis 数据库,可是客户端只有同个内网的一个 Ruby on Rails 的应用,怎么会有链接数爆掉的可能?数据库
老衲掐指一算:安全
redis-store
gem 源码,默认链接池大小应该是 5,10个 unicorn 工做进程,按需链接,最大值是 10 x 5 = 50。在不考虑其余可能还用到 Redis 链接的状况下,目前已知的最大 Redis 链接数需求是 122,这个数远小于 Redis 理论最大链接数啊,并且当时显示链接数到达上万!并且这个项目已经不多访问,压力极其小,不大可能会达到理论所需链接数啊!服务器
必定是有某种神秘力量在主导这一切!!!网络
以上理论最大链接数分析只是定性分析,只能大概说明有一些诡异的东西存在,而想真正确认问题根源,还得作定量分析,只有数据才能说明一切!ide
事不宜迟,要采集数据,第一步就是加监控,因此当时就紧急写了一个定时采集 Redis 客户端数量(使用 redis 内建 CLIENT LIST
命令)的脚本,结合 crontab 定时运行,将结果写入文件,做为后续分析的基础。spa
经过监控脚本,发现几个有意思的现象:code
在有了上一步的发现以后,我继续用系统命令 sudo netstat -apnt
检查 6379
端口链接数发现,客户端机器也才只有 42 个左右的链接到 redis 服务器端,结合最开始的理论链接数分析,这个数量是比较合理的。server
可是!可是!反过来去服务端机器用一样的命令检查,在服务端视角,却有多达300+个客户端创建的链接,并且都是在 ESTABLISHED 状态!这个数量和上面另外一种监控方式获得的数量一致!进程
究竟是什么状况?还能有这种操做?
至此,Redis 链接数泄露是板上钉钉的事情了,但是又是为何呢?为此,我在网上搜索了不少问答跟文章,后来总算找到了答案,果不其然,仍是默认配置的问题。
redis 为了不客户端链接数过多,有一个timeout配置,意思是若是链接的空闲时间超过了timeout的值,则关闭链接。默认配置是0,意思是没有超时限制,永远不关闭链接。生产上显然不会配置0……
![]()
OMG!赶忙打开咱们的 redis 的配置文件验证是否如此,果不其然,redis一直保持着默认配置!
至此,很好解释为何链接数会泄露了,由于有不少空闲或者实际上客户端已经断开的链接,在服务器端一侧仍然保持着。那什么状况会致使这样的状况发生呢?
我猜想:
找到问题根源以后,修复起来就简直太简单了。事实上,开发领域就是如此,绝大部分时间都花在了找 bug 上,而改掉bug,可能只须要一分钟不到。
首先,修改了下 redis 数据库配置:
成功重启 redis 以后,从新运行前面的监控脚本,以便观察修复后状况,初步能够确认这下服务器端和客户端的链接数一致了:
再又通过几天的脚本自动采集数据后分析,系统又恢复平稳运行了,链接数一直稳定在理论最大链接数之下。
这个问题的根源其实很小,可是排查过程仍是花了挺多时间,主要是须要等待采集到足够的数据后用于分析。其余心得体会:
0.0.0.0
来源请求的安全漏洞;