redis pub/sub 断线必丢消息,因其纯内存广播设计:不持久化、不存offset、不重发,重连后仅接收新消息;可靠替代方案为stream或list+pub/sub混合模式。

Redis Pub/Sub 断线就丢消息,不是配置能修的 Bug,是设计使然。它不存消息、不记 offset、不重发——只要客户端连接断开哪怕 100ms,期间所有 PUBLISH 都永久消失。
为什么重连后收不到断连期间的消息
Pub/Sub 是纯内存广播模型:消息只推给当前在线的 SUBSCRIBE 连接,服务端不留痕。重连后执行 SUBSCRIBE,只是重新开启“从现在开始收”的开关,历史消息不存在,也无处可查。
- 常见现象:服务重启、网络抖动、K8s Pod 重建后,日志里完全看不到断连那几秒的消息记录
- 误操作高发点:用
redis-cli手动连上新 Master 后直接SUBSCRIBE,以为能“捞回”数据——实际不可能 - PSUBSCRIBE 通配符订阅同样不回溯,和频道名无关,和连接状态强绑定
client-output-buffer-limit 导致的静默断连
订阅者处理慢 → Redis 输出缓冲区堆积 → 触发 client-output-buffer-limit pubsub 硬限制 → 连接被服务端强制关闭,且不报错。这是生产环境最隐蔽的丢消息原因。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 默认限制是
client-output-buffer-limit pubsub 32mb 8mb 60:缓冲区持续 60 秒超 8MB 就断连 - 典型诱因:消息体大(如 JSON 超 50KB)、消费逻辑含同步 I/O(如调外部 HTTP 接口)、未异步分发导致主线程阻塞
- 验证方式:查 Redis 日志是否有
Client X disconnected, output buffer too large;或用CLIENT LIST看omem字段是否长期 >2MB - 临时缓解可设为
client-output-buffer-limit pubsub 0 0 0,但官方明确不推荐——掩盖问题而非解决
真正可用的补漏方案只有两个方向
要么换底层机制,要么在应用层兜底。别在 Pub/Sub 上硬扛可靠性。
-
换 STREAM:用
XADD mystream * data发,XREADGROUP GROUP g1 c1 COUNT 10 STREAMS mystream >拉,支持 ACK、位点、消费者组、持久化。这是官方推荐的替代路径 -
List + Pub/Sub 混合:发布端先
LPUSH queue:events ...存数据,再PUBLISH channel:events 1发轻量通知;订阅端启动时先LRANGE queue:events 0 -1补读,再SUBSCRIBE channel:events - 注意顺序:必须
LPUSH在前、PUBLISH在后,否则通知发了但数据没写进去,补漏逻辑失效 - 别用 AOF/RDB 或 Sentinel 做幻想:它们完全不记录 Pub/Sub 流量,切换主从后新节点上没有任何“待消费消息”
最易被忽略的一点:Pub/Sub 的“即时性”和“不可靠性”是一体两面。你越依赖它做关键状态同步(比如订单支付成功通知库存扣减),就越需要在业务层加 MySQL 写入+定时比对这类双重保障——而不是指望 Redis 自己变可靠。










