背景

最近有用户报使用PHP客户端predis访问阿里云Redis(原KVStore)时,会出现connection refused错误,用户怀疑是因为后端连接数超了,导致连接被拒绝,但是监控看连接数并没有超过阈值,进而怀疑是后端redis的连接数限制逻辑有问题,经过排查发现连接数限制逻辑并没有问题,下面说下具体的排查过程。

排查过程

通常通过socket进行网络通信,出现connection refused错误,主要是由于以下原因引起的,

  • 目标端口没有打开,可能是监听端口的进程的已经挂了
  • 有防火墙阻塞连接,客户端发过来的包直接被丢弃掉
  • 监听端口对应的tcp backlog已经满了
  • 网络质量问题

用户怀疑报connection refused是因为后端连接数限制逻辑有问题,首先来排除这个原因。

实际上根据后端实现,当连接数超限时,会向客户端返回明确的错误信息,实际测试也可以发现,predis抛出的异常信息不是connection refused,而是比较直观的错误信息,如下,

max number of clients reached

后端Redis挂了,这个可能性很小,直接看redis日志即可排除。防火墙的问题,在目前云Redis服务上也不存在相关设置,可以排除。

监听端口对应的tcp backlog满了,这个是一个可能性比较大的原因,之前也确实出现过因为backlog设置的过小导致连接拒绝的情况,执行netstat -s | grep -i listen,如果有如下信息且数字还在增长,就基本可以确定是backlog的问题了,更具体的信息可以通过tcpdump抓包获取,

10809 times the listen queue of a socket overflowed
    10809 SYNs to LISTEN sockets ignored

但是之前我们就在异常实例的机器上调整过系统的somaxconn参数和redis本身的backlog参数到一个比较大的数值,所以发生connection refused并非是因为tcp backlog满了。

那基于排除法,应该是网络本身的异常导致的问题了,这个时候就要借助于我们强大的后台监控系统天象了,依托天象,我们可以看到,客户机到后端DB机器,在指定时间段内的网络质量情况,从天象上可以看到如下信息,

redis error 101错误 redis报错connection refused_网络

我们可以看到在连接拒绝期间,没有listen drop和listen overflow的情况,但是TCP重传率很高,有此可以肯定是在TCP建立连接时,三次握手超时导致出现connection refused错误。

总结

当问题出现时,细心排查很重要,但是如果有一个强大的后台支撑系统,能够提供各种实时和历史信息,辅助我们进行排查,往往可以起到事半功倍的效果。况且很多时候,发现问题时,问题已经是过去式了,这个时候借助于这种平台可能就是排查问题的必须条件了,这里必须要赞下我们强大的天象系统了!