如果你不知道要到哪儿去,那通常你哪儿也去不了。
这三天,一直在弄一件事情,就是redis订阅时,怎么在订阅的连接上,给server端发保活报文。
1. 问题
redis subscribe有时候会有死链,但server端该连接已经不存在。
2. 复现方法
在redis订阅成功后,client上添加iptables规则,把与server端通信报文丢弃。
240s后,(因为server端的tcp-keepalive 设置的是120s),server端因为保活无回应,关闭了该连接。
而client端一直保持一个established的连接,且一直保持,永不断开。
3. 解决方法
把py-redis版本升级到2.10.3后,该版本拥有socket-keepalive参数,能够在订阅后对该通道保活。
配置参数如下:
1
2
3
4
5
6
7 r=redis.StrictRedis(host=self.srvip,port=self.port,password=self.passwd,socket_connect_timeout=15,socket_keepalive=True,socket_keepalive_options={
socket.TCP_KEEPIDLE:120,
socket.TCP_KEEPCNT:2,
socket.TCP_KEEPINTVL:30
})
rl=r.pubsub()
rl.subscribe(self.subch)
关键参数:
socket_keepalive
,socket_keepalive_options
socket_keepalive
为True
时代表开启TCP保活功能。socket_keepalive_options
值是字典格式,有如下三个参数:
socket.TCP_KEEPIDLE
: 空闲多少秒后开始检测socket.TCP_KEEPCNT
: 检测的包数量socket.TCP_KEEPINTVL
: 检测包发送间隔
4. Redis变更日志
参考地址:
https://github.com/andymccurdy/redis-py/blob/master/CHANGES
该功能添加在2.10.0版本中:
- 2.10.0
- Added TCP Keep-alive support by passing use the socket_keepalive=True
option. Finer grain control can be achieved using the
socket_keepalive_options option which expects a dictionary with any of
the keys (socket.TCP_KEEPIDLE, socket.TCP_KEEPCNT, socket.TCP_KEEPINTVL)
and integers for values. Thanks Yossi Gottlieb.