Redis 的 Pub/Sub 和 Stream 有什么区别?消费者离线后还能收到消息吗?
下面是一段教学用的模拟面试。
🧑💻 面试官:Redis 的 Pub/Sub 和 Stream 有什么区别?
🙋♂️ 我:Pub/Sub 是发布订阅,Stream 是消息队列,能保存历史消息。
🧑💻 面试官:消费者拿到 Stream 消息以后崩溃,消息会自动发给另一个消费者吗?
🙋♂️ 我:需要处理未确认消息和重新认领。
🧑💻 面试官:那确认以后,条目是不是就从 Stream 删除了?如果同一个订单处理两次,又怎么办?
先分开三件事:「留下消息」「分配处理」「确认完成」。有消息记录,不等于故障后的处理会自动全部完成。
面试速答(60 秒版)
Redis Pub/Sub 面向实时广播。发布时把消息推给当前订阅者,不为离线订阅者保留一份以后补读的历史,交付语义是 at-most-once。
Stream 则先把消息保存为带 ID 的条目,可以按进度读取。使用消费组时,组内消费者分工处理消息,交付但未确认的消息会进入 Pending 列表;成功处理后用 XACK 确认。
消费者故障后,需要读取自己的 Pending 或通过认领机制接管其他消费者的超时未确认消息。XACK 清的是未确认记录,不是删除 Stream 条目。
因此,离线补读要看消息是否仍被保留,可靠性还受持久化、复制和裁剪配置影响。实时通知可以考虑 Pub/Sub;需要补读和消费进度,可以考虑 Stream,同时设计重试与幂等,不能承诺“用了 Stream 就绝不丢、不重复”。

知识点详解:消息存下来以后,还需要管理哪些状态?
Pub/Sub 是广播,不是给离线用户留信箱
咱们假设后台发布一条“订单 42 已支付”的通知。
Pub/Sub 可以让当前在线的订阅者立即接收。如果某个消费者此时断开,重新订阅以后不会自动补上错过的那条消息。发布返回的订阅者数量,也不等于这些消费者的业务操作都成功了。
这适合一些允许丢失、可以靠后续状态刷新补偿的通知。不适合仅凭这条广播保证扣款、发货等关键任务一定执行。
Stream 先记录条目,再由消费者读取
同一条通知通过 XADD 进入 Stream,就有了消息 ID 和字段。消费者可以按 ID 或消费进度读取历史,而不是只接住发布那一刻。
但补读成立的前提是条目还在。Stream 被裁剪、删除,或者故障中未按预期持久化、复制,都会影响可恢复范围。因此“支持历史读取”和“任何故障都不丢”必须分开。
下面是 Redis CLI 的单条教学流程,不是完整可靠消费者:
XADD orders * order_id 42 event paid
XGROUP CREATE orders workers 0 MKSTREAM
XREADGROUP GROUP workers worker-a COUNT 1 STREAMS orders >
组从 0 建立,能够读取已有条目;这里的 > 用于请求该组尚未交付的新消息,不能把它当成“顺便把所有 Pending 也重放”。实际消息 ID 由 XADD 返回。
PEL 记录“交付过,但还没有确认完成”
使用普通消费组读取、没有指定 NOACK 时,消息交给 worker-a,会记入该组的 Pending Entries List,简称 PEL。
假设 worker-a 拿到消息后就崩溃了。Stream 条目还在,PEL 也知道这条消息未确认,但是业务处理不会凭空完成。恢复程序可以读取自己的未确认消息,或者让其他消费者通过 XCLAIM、XAUTOCLAIM 等机制认领适当的超时消息。
认领需要消费者主动执行并继续处理,不能背成“到了时间 Redis 就一定自动重投给健康消费者”。同时还要设置合理的空闲时间,避免把仍在正常处理的长任务抢走。
处理成功后执行 XACK,移除这条消息的 PEL 记录。消息条目本身还可以保留在 Stream 中;删除条目是另外的动作。两份状态要分开看。

一组内分工,多组之间各有进度
假设发货系统和报表系统都需要处理订单事件,可以建立两个消费组,它们各有自己的进度和未确认记录。
同一组里的 worker-a、worker-b 分工读取新消息,不是每个人都独立收到一份广播。不同组则可以独立处理同一条 Stream 记录。
消费者可能完成业务后、确认前崩溃。后来重试会再次处理同一消息,所以发货等动作要用订单 ID、事件 ID 等保证幂等,不能依靠 XACK 宣称业务绝不会重复。
完整消费者还需要读取、错误重试、认领、确认与退出管理,上面的三个命令只是帮助理解流程。语义依据 Redis Pub/Sub 与 XACK 等官方说明核验。

面试官继续追问
消息读到了,是不是就应该马上 XACK?
要先完成本次要求的处理,再确认。如果提前确认后业务失败,组的未确认机制就不再代表这次未完成工作。业务完成与确认之间仍需幂等处理。
一直不裁剪,是不是最安全?
内存可能持续增长。需要按保留时长、容量与消费进度设计裁剪,还要考虑未处理消息,不能只为省内存删掉消费者仍需要的数据。
面试速记卡
- Pub/Sub:实时广播,离线不自动补读,at-most-once。
- Stream:保存带 ID 的消息条目,支持按进度读取。
- 消费组:组内分工,组间独立。
- Pending:交付未确认,故障恢复需要读取或认领。
- XACK:移除未确认记录,不等于删除 Stream 条目。
- 可靠性:结合持久化、复制、裁剪与幂等,不承诺绝不丢、不重复。
公司面试真题
这道题暂未收录可核验的公司真题来源。你可以先阅读本文解析,或浏览已收录的公司面试真题。
浏览公司面试真题 →