Redis连接问题研究
问题研究#
近日在生产环境中出现了一种情况:有时代码向Redis发消息时会卡住很长时间。
初步怀疑是网络问题,因为代码中使用了长连接,在生产环境改为短链接后问题消失。
为进一步探究原因,在开发环境中模拟各种情况,发现在Redis重启或者连接正常关闭时,都没有问题,程序会立即发现连接异常并发起新的连接。
最后在模拟非正常关闭的连接时复现了生产环境的问题,模拟的就是连接看起来正常,但是服务端不处理Socket数据时的情况。(TCP dead peer)
模拟方式如下:
-
使用socat程序代理Redis到另外的端口:
socat TCP4-LISTEN:6378,fork TCP4:127.0.0.1:6379
-
修改代码连接新的端口,在连接建立后,在shell中使用 CTRL+Z 将socat程序挂起
此时程序再发送消息就会卡住很长时间了。
应对方法#
短链接#
在系统可以承受的情况下,使用短链接是很方便的解决办法。
keepalive#
使用keepalive可以定时探测连接的对端是否还活着,同时也可以避免某些网络设备关闭不活跃的连接。
timeout#
为避免在连接出问题时等待太长时间,可以设置一个较短的超时时间,这样可以感受更好一点吧。
连接池#
如果底层提供了连接池应优先使用连接池,避免手工维护一个长连接。
参考连接#
https://stackoverflow.com/questions/6116382/how-to-reproduce-a-silently-dropped-tcp-ip-connection