redis pub/sub 不支持自动重连,所有客户端断连后均丢失订阅状态,必须手动重建连接并全量重订阅;生产环境需采用指数退避重试、心跳检测及 list+pub/sub 混合模式兜底。

Redis Pub/Sub 本身不支持自动重连,所有客户端库(redis-py、ioredis、Jedis、lettuce、redigo)在连接断开后都会丢失订阅状态,必须手动重建连接并重新调用 subscribe() 或 psubscribe()。
redis-py 的 listen() 断连后直接抛 ConnectionError,不能靠外层 try/catch 捕获
redis-py 的 pubsub.listen() 是阻塞迭代器,一旦底层连接中断,它会立即抛出 ConnectionError 并退出循环——不是静默失败,而是彻底终止。这意味着你不能只在 for msg in p.listen(): 外包一层 try/except 就完事。
- 正确做法:把整个
listen()循环包进while True:,并在捕获ConnectionError后,**新建Redis实例和PubSub对象**,再调用subscribe('a', 'b', 'c')全量重订 - 别复用旧的
PubSub实例:它内部状态已损坏,继续调用subscribe()可能无响应或报ConnectionClosedError - 重连间隔至少
time.sleep(1),生产环境务必用指数退避(如 1s → 2s → 4s → 最大 30s),否则集群重启时可能触发 Redis 的maxclients限制
ioredis 的 connect 事件比 ready 更适合触发重订阅
ioredis 的 ready 事件只在首次连接完成认证、脚本加载和 pub/sub 状态同步后触发一次,后续重连成功不会再次触发。若监听 ready 来恢复订阅,重连后永远不执行。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 应监听
connect事件(每次 TCP 连接建立即触发),但注意:此时客户端可能尚未完成 auth 或命令队列初始化 - 稳妥写法是
client.on('connect', () => setImmediate(() => client.subscribe('ch'))),让事件循环让出控制权,确保就绪 - 避免在
reconnecting事件里做任何操作——此时连接还没建好,subscribe()必然失败 - 若用
Redis.Cluster,需监听cluster:connect而非connect,事件名不同
Lettuce 启用 autoReconnect 后仍需手动恢复订阅
Lettuce 支持 autoReconnect(true),但它只重建底层 TCP 连接,**不会自动同步订阅关系到服务端**。这是最容易忽略的坑:连接看似恢复了,但 subscribe() 没重发,消息就收不到。
- 必须配置
ClientOptions.builder().autoReconnect(true).disconnectedBehavior(RECONNECT_AND_QUEUE_COMMANDS),否则重连期间命令会被丢弃 - 监听
StatefulRedisPubSubConnection的onConnected回调,在其中调用connection.sync().subscribe("ch") -
spring.redis.lettuce.pool配置对 Pub/Sub 无效——Pub/Sub 使用独占长连接,不走连接池 - 若误配
RedisClusterClient地址,订阅会静默失败(Redis 集群模式不支持 Pub/Sub)
重连时漏订频道、重复订阅、资源泄漏是高频事故点
重连逻辑写错,轻则收不到部分消息,重则引发 goroutine 泄漏、连接数爆满或 Redis maxclients 被打满。
- 多个频道必须一次性全量重订:
subscribe('a', 'b', 'c'),不能只补订'a'而漏掉'c' - Java 中用
Jedis重连前,必须先jedis.close(),否则旧连接未释放,新连接不断创建,很快触达maxclients - Go 中用
redigo,每次重连前要conn.Close(),且dial必须设ConnectTimeout,否则网络卡死时 goroutine 永久阻塞 - 所有客户端都建议加心跳:每 15–30 秒发
PING并等待PONG,TCP keepalive 默认 300 秒太迟,无法及时发现僵死连接
真正可靠的方案不是死磕 Pub/Sub 重连,而是接受它“断连即丢”的设计本质——用 List + Pub/Sub 混合模式兜底:发布端先 LPUSH 数据再 PUBLISH 通知;订阅端重连后先 LRANGE 补数据,再 SUBSCRIBE 新消息。这才是生产环境少踩坑的务实路径。










