redis pub/sub连接在sentinel主从切换后断开,因其是纯内存无状态长连接,不走复制流、不持久化,master进程退出即连接失效;客户端须主动监听+switch-master事件、重建连接并重订阅。

Redis 发布订阅模式本身不保证消息可靠性,Master 宕机时未被消费的消息会永久丢失;Sentinel 无法让 pub/sub 消息“自动续传”,它只负责切换主从角色和通知客户端新地址——消息中断必须靠客户端主动重连+重订阅来恢复。
为什么 Sentinel 切换后 pub/sub 连接会断开
Redis 的 PUBSUB 连接是纯内存、无状态的长连接,不经过 Redis 复制流,也不写 AOF/RDB。一旦客户端连接的 Master 进程退出(哪怕只是被 Sentinel 切走),该连接立即失效,所有未 SUBSCRIBE 的频道监听都会丢失。
常见现象包括:
- 客户端收不到新发布的消息,但
redis-cli连新 Master 能正常SET/GET - 日志里看到
+switch-master,但业务侧 pub/sub 流量归零 - 客户端没报错,只是“静默失联”——因为 TCP 连接可能还没触发 FIN,应用层没感知断连
客户端必须自己处理重连与重订阅
Sentinel 不会、也不能帮你维持 pub/sub 上下文。真正起作用的是客户端是否实现了以下逻辑:
- 监听
SENTINEL get-master-addr-by-name <mastername></mastername>或订阅__sentinel__:hello频道,捕获+switch-master事件 - 检测到连接断开(如
read: connection reset by peer或心跳超时)后,关闭旧连接 - 用新 Master 地址重建 TCP 连接,并重新执行全部
SUBSCRIBE命令(顺序和频道名必须一致) - 如果依赖消息顺序,需在应用层加序列号或时间戳,并容忍少量重复(因重连窗口内可能漏收)
示例伪代码逻辑:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
on pubsub_connection_lost:
addr = sentinel.get_master_addr_by_name("mymaster")
conn = redis.connect(addr)
conn.subscribe("channel_a", "channel_b") // 必须显式重订
resume_from_last_known_offset() // 若用外部存储记录 offset
sentinel down-after-milliseconds 和 failover-timeout 对 pub/sub 中断时长的影响
这两个参数不改变 pub/sub 丢消息的本质,但直接影响“从中断到恢复”的总耗时:
-
down-after-milliseconds设得过大(如 30000),主节点真挂了,哨兵要等满这个时间才开始投票 → pub/sub 中断至少 +30s -
failover-timeout设得太小(如 5000),可能新主刚选出来、从库还没完成同步,客户端就连过去 → 订阅失败或收到过期数据 - 推荐组合(内网环境):
down-after-milliseconds 8000,failover-timeout 40000;跨云场景直接用15000和180000
注意:parallel-syncs 虽然影响从库同步速度,但它只作用于 SYNC/PSYNC 流程,对 pub/sub 连接重建无直接关系。
真正能降低 pub/sub 中断影响的实操点
不要指望 Sentinel 自动兜底,而是把恢复控制权交还给客户端和架构设计:
- 所有 pub/sub 客户端必须实现带退避的自动重连(指数退避,避免雪崩)
- 关键频道建议启用 Redis Stream(
XADD/XREAD)替代 pub/sub,Stream 支持消费者组、ACK、历史回溯 - 如果必须用 pub/sub,可在发布端加一层本地队列(如 Kafka / RabbitMQ)做缓冲,再由 worker 推送到 Redis,把“不可靠传输”转为“至少一次”语义
- 监控项不能只看
+switch-master,要同时采集客户端连接数、订阅频道数、PONG 延迟,才能准确定位是 Sentinel 问题还是客户端没响应
最常被忽略的一点:很多 SDK(比如 Jedis、StackExchange.Redis)默认不监听 Sentinel 事件,也不会自动重订阅 —— 你得亲手补上这部分逻辑,而不是以为配好 sentinel.conf 就万事大吉。










