如果你不知道要到哪儿去,那通常你哪儿也去不了。

这三天,一直在弄一件事情,就是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**值是字典格式,有如下三个参数:

  1. socket.TCP_KEEPIDLE: 空闲多少秒后开始检测
  2. socket.TCP_KEEPCNT: 检测的包数量
  3. 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.