redis pub/sub 从设计上放弃消息可靠性,无存储、无持久化、无消费进度管理,消息仅内存广播且瞬时丢弃,无法满足“至少一次投递”或断连补发需求。

Redis Pub/Sub 从设计上就放弃消息可靠性,这不是配置能修好的问题,而是协议层直接不支持。
Pub/Sub 没有消息存储,只做内存广播
所有消息仅在 publish 执行瞬间推给当前活跃的订阅连接,之后立即从 Redis 内存中清空。没有队列、不写磁盘、不进 RDB/AOF——哪怕 Redis 实例正常运行,只要订阅者没连上、或连上了但处理慢导致缓冲区溢出,消息就永远消失。
-
pubsub numsub channel返回 0 时发消息,必然丢 - 用
redis-cli SUBSCRIBE channel后再断开重连,之前发布的消息完全不可见 - 集群模式下,
PUBLISH只发到当前节点,不跨节点广播,主从切换窗口期的消息可能只存在于已下线节点内存中
没有消费进度管理,重连即“从零开始”
Redis 不记录任何 offset、不维护 consumer group、不区分“新老订阅者”。SUBSCRIBE 命令只是把客户端加进一个链表,一旦连接中断,这个链表节点就被销毁,未读缓冲区(netty 或 socket rx queue)里的数据直接丢弃,没有任何回溯能力。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- Java 中 Lettuce 默认 netty 接收缓冲区 16KB,处理延迟 >50ms 就容易填满触发强制断连
- Python 的
pubsub.get_message()超时返回None,不代表没消息,很可能缓冲区已被冲掉 - 监控上看到
connected_clients骤降 +pubsub_channels突变,基本就是消费者崩溃导致批量丢消息
协议层无 ACK,发布成功 ≠ 消息送达
PUBLISH 命令返回整数(发送给多少个订阅者)只表示“当时有多少个在线连接”,不校验这些连接是否真的收到了、是否处理完了。TCP 层断连、内核丢包、应用层未及时 read,Redis 全然不知,也绝不重试。
- 网络抖动 100ms,
PUBLISH返回 1,但订阅端get_message()什么也没拿到 - 用
PSUBSCRIBE pattern监听通配符,某次断连后重连,pattern 匹配逻辑重新计算,可能漏掉中间几条关键事件 - 多个服务共用一个
SUBSCRIBE连接,其中一个处理慢拖垮整个连接,其他消费者一起失联
真正难的不是换用 XADD 和 XREADGROUP,而是接受一个事实:Pub/Sub 从来就不是为“不丢消息”而生的。它适合发“现在正在发生的事件”,比如监控指标推送、实时聊天室广播;一旦业务要求“至少一次投递”或“断连后补历史”,就必须切到 STREAM 或外部 MQ——否则所有运维调优、重试封装,都是在对抗设计契约。










