Redis连接问题研究

问题研究#

近日在生产环境中出现了一种情况:有时代码向Redis发消息时会卡住很长时间。

初步怀疑是网络问题,因为代码中使用了长连接,在生产环境改为短链接后问题消失。

为进一步探究原因,在开发环境中模拟各种情况,发现在Redis重启或者连接正常关闭时,都没有问题,程序会立即发现连接异常并发起新的连接。

最后在模拟非正常关闭的连接时复现了生产环境的问题,模拟的就是连接看起来正常,但是服务端不处理Socket数据时的情况。(TCP dead peer)

模拟方式如下:

  1. 使用socat程序代理Redis到另外的端口:

    socat TCP4-LISTEN:6378,fork TCP4:127.0.0.1:6379
    
  2. 修改代码连接新的端口,在连接建立后,在shell中使用 CTRL+Z 将socat程序挂起

此时程序再发送消息就会卡住很长时间了。

应对方法#

短链接#

在系统可以承受的情况下,使用短链接是很方便的解决办法。

keepalive#

使用keepalive可以定时探测连接的对端是否还活着,同时也可以避免某些网络设备关闭不活跃的连接。

timeout#

为避免在连接出问题时等待太长时间,可以设置一个较短的超时时间,这样可以感受更好一点吧。

连接池#

如果底层提供了连接池应优先使用连接池,避免手工维护一个长连接。

参考连接#

https://stackoverflow.com/questions/6116382/how-to-reproduce-a-silently-dropped-tcp-ip-connection

https://redis.io/docs/reference/clients/#tcp-keepalive

comments powered by Disqus