SUBSCRIBE后收不到之前消息是因为Redis发布订阅是即发即弃模式,消息不落盘、不缓存、不排队;只有在订阅状态下发布的消息才能被接收。

为什么 SUBSCRIBE 后收不到之前发布的消息
因为 Redis 的 PUBLISH/SUBSCRIBE 本质是“即发即弃”(fire-and-forget):消息不落盘、不缓存、不排队。只要没有客户端正在 SUBSCRIBE 某个频道,那条消息就彻底消失——连 Redis 自己都不记得它存在过。
- 现象:你先
PUBLISH "hello",再开新终端SUBSCRIBE channel,永远收不到那条"hello" - 原因:Redis 的发布订阅模块压根不维护消息队列,只做内存级广播中转
- 对比记忆:这不像 Kafka 或 RabbitMQ,它甚至不如 Redis 自家的
LPUSH/BRPOP队列——后者至少消息还留在 list 里
用 Redis Stream 替代 pub/sub 实现消息回溯
从 Redis 5.0 开始,Stream 是官方推荐的、可持久化、可回溯的消息模型。它天然支持“消费者组”“消息 ID 定位”“历史拉取”,正好补上 pub/sub 缺失的“读历史”能力。
- 写入:
XADD mystream * sensor_id 123 temp 24.5——*表示自动生成时间戳+序列 ID - 读历史:
XREAD COUNT 10 STREAMS mystream 0-0从头读 10 条;XREAD COUNT 1 STREAMS mystream $只读最新一条 - 关键区别:
Stream数据默认持久化到 RDB/AOF;即使服务重启,消息仍在
pub/sub 和 Stream 在连接与缓冲上的隐性差异
很多人切到 Stream 后还是丢消息,其实是卡在了客户端连接行为和 Redis 输出缓冲限制上。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- pub/sub 客户端有硬性缓冲限制:
client-output-buffer-limit pubsub 8mb 2mb 60,超限直接断连(尤其在慢消费或网络抖动时) - Stream 没这个限制——它是普通命令交互,走的是常规 client buffer,不受 pubsub 专用策略约束
- 但注意:
XREAD BLOCK是阻塞命令,若客户端意外断开,未 ACK 的消息仍会留在 stream 中,需配合XACK手动标记(否则重复消费)
什么时候该坚持用 pub/sub,而不是强行上 Stream
不是所有场景都需要回溯。如果只是“通知类广播”——比如刷新缓存、踢下线、触发 webhook——pub/sub 依然更轻、更快、更解耦。
- 适用 pub/sub:实时告警、状态同步、事件广播(不要求 100% 投递)
- 必须换 Stream:需要重放、审计、补偿、多消费者分片处理、或下游偶尔离线
- 陷阱提醒:别为了“看起来更高级”而用 Stream 替换简单通知——
XADD比PUBLISH多约 3 倍内存开销,ID 索引也带来额外 CPU 成本
真正难的不是选哪个命令,而是想清楚“这条消息丢了能不能接受”。很多线上问题,其实是在用 pub/sub 做 Stream 的事,又没配好重连和幂等,最后卡在“以为发了,其实没人收到”上。

















