0%

记一次线上Redis警报

这周周五收到了两个不同系统的Redis集群警报,无独有偶,都是提示连接数超过80%。这个问题在公司其他系统挺常见的,在此记录一下。

问题排查

前置信息

  • 应用A是一个NodeJS应用,部署在VMWare的虚拟机上已经在线上运行了400多天;

  • 应用B是一个Scala应用,部署在私有化的Azure Container Service(ACS)上,周三刚进行了更新;

  • 应用A和B在物理和业务上都没有关联;

  • Redis集群为一主两从,单个节点大小为5G,版本为3.2。系统A的Redis集群为15G,系统B为120G

  • 警报提示Redis服务器的连接数超过了3200,原上限为4000。

线上情况

首先在监控界面上可以观察到,两个Redis集群所以的中有几个节点连接数超了3200,各个节点的连接数不一样。

那么可以初步推断不是应用的问题,因为应用连接Redis集群会连接所有的节点,正常情况下每个节点的连接数都是大致一样的。随后就在检查了应用A和B所在主机的TCP连接数,果然发现与Redis相关的连接很少。

然后我们登录进了Redis终端,使用CLIENT LIST来查看当前服务器的连接情况。发现了大量空闲的连接,存活时间最长的有近400天。

1
2
3
redis x.x.x.x:6379> CLIENT LIST
id=x addr=x.x.x.x:xx fd=6 age=19089992 idle=19089992 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 events=r cmd=cluster
...

这让我突然想起了前一段时间,ACS平台发的一则通告。通告中提醒,ACS平台由于底层的特性,TCP连接会在闲置240s后自动断开,平台的同事提醒开发们要留意会不会对应用造成影响。

回到这个问题上,上述的空闲连接应该是应用异常退出没有发送FIN包或者网络异常导致FIN包发送失败。在Redis服务端没有察觉到该连接已经是死掉的链接,经过长时间的积累,这样无用的连接积累到一定的程度触发了报警。

查了查Redis与之相关的参数,有timeout和tcp-keepalive两个:

  • timeout不为0时,服务端上的连接空闲一段后自动断开;
  • tcp-keepalive不为0时,服务端定时发送ACK包到客户端,来检测这条连接是否存活。

而服务器配置上的两个参数都为0,即都为关闭状态,所以只要FIN包没有正常发送到服务器,这条连接就会一直保留。

找到了根源那问题就好解决,由于Redis支持配置的热修改,我们直接设置timeout为240s tcp-keepalive为30s。过了几秒后,Redis集群的各个连接数降到正常范围内,问题完美解决。

总结改进

其实ACS平台的同事早有提醒 ,只不是是我们没有想到对Redis服务器有影响。为了避免这个问题,所有的Redis集群的默认配置都应该加上这两个参数。