redis pub/sub本质是内存广播喇叭,publish后立即分发至活跃连接并释放,不存历史、不等ack、不落盘,断连即丢消息。

Redis PUB/SUB 从不打算做可靠消息队列,它本质上是内存里的“广播喇叭”,不是“挂号信邮局”。
为什么 PUBLISH 后就不管了
Redis 的 PUB/SUB 在协议层就是纯内存转发:收到 PUBLISH channel msg,立刻遍历当前所有订阅该 channel 的活跃连接,把消息拷贝一份塞进每个连接的输出缓冲区,然后——释放。不记 offset、不存历史、不等 ACK、不落盘。哪怕只有一条消息,发给 100 个客户端,就是 100 次独立内存写入+立即丢弃原始副本。
常见错误现象:
- 用
redis-cli SUBSCRIBE ch启动后 Ctrl+C 再重连,之前发的消息全没了 - Java 用
JedisPubSub处理消息时发生 GC 停顿 2 秒,这期间所有PUBLISH全部消失 - 服务端日志里反复出现
Client closed connection due to output buffer limit,其实是缓冲区爆了被强制断连
client-output-buffer-limit pubsub 不是兜底,而是熔断开关
很多人以为调大这个配置就能“防丢”,其实它只是延迟丢得更晚一点。一旦订阅者消费慢(网络卡、应用忙、反序列化耗时),消息就在它的输出缓冲区里堆积;硬限一到,Redis 直接 close(fd),缓冲区清空,连接状态归零——连“重连后从哪继续”这种问题都不用回答,因为压根没维护过位置。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
参数差异很关键:
- 默认值
client-output-buffer-limit pubsub 8mb 2mb 60:硬限 8MB,软限 2MB 持续 60 秒就断 - 改成
32mb 8mb 60只是把断连点往后推,但缓冲区仍不持久化,断连即丢全部积压 - 设成
0 0 0更危险:失去保护,OOM 直接拖垮 Redis 实例
什么场景下可以放心用 SUBSCRIBE
它适合的是“丢了也不影响业务正确性”的信令类场景,比如:
- 实时指标推送(CPU 使用率、QPS 曲线),旧数据本来就没意义
- DevOps 事件总线(部署完成、配置热更),失败可由下一次心跳覆盖
- 前端页面状态广播(“XX 用户已上线”),用户刷新页面就重订
但凡涉及订单创建、支付回调、库存扣减这类需要“至少一次送达+业务幂等”的逻辑,SUBSCRIBE 就不该出现在架构图里。
真正难的不是换命令,是改思维
把 PUBLISH/SUBSCRIBE 换成 XADD/XREADGROUP 很容易,难的是让业务代码承担起消息生命周期管理责任:谁创建消费者组、谁调 XACK、断连后怎么补 XRANGE、积压量怎么告警、XTRIM 阈值怎么定。这些不是 Redis 配置能解决的,得嵌进业务逻辑里去。










