redis stream 不是 pub/sub,而是可靠有序可回溯的消息队列;需用 xadd + xreadgroup + ack 配合独立消费者组实现类 pub/sub 功能,且必须手动建组、ack 和运维游标。

Redis Stream 本身不提供“发布/订阅”语义,它实现的是**可靠、有序、可回溯的消息队列**。想用 Stream 达到类似 Pub/Sub 的效果(比如广播给多个服务),必须靠消费者组(Consumer Group)+ 多个独立组来模拟,而不是直接替换 PUBLISH/SUBSCRIBE。
为什么不能直接用 XADD + XREAD 当作 Pub/Sub?
因为 XREAD 是单次拉取、无状态、不记录偏移的读法:所有调用者都从同一 ID 开始读,消息会被重复消费;没有自动游标管理,无法区分“谁读了哪条”;离线后无法续读——这和 Pub/Sub 一样不可靠,甚至更难维护。
-
XREAD STREAMS stream_name 0-0每次都从头读,不是“订阅”,是“快照拉取” - 没消费者组时,
XREAD不保存进度,重启或断连即丢失上下文 - 无法做到“一条消息只被某组内一个消费者处理”,天然不支持负载均衡
真正可靠的方案:XADD + XREADGROUP + ACK
核心是把每个业务方建一个独立的消费者组(比如 group-order、group-inventory),它们互不影响,各自维护自己的 last-delivered-id。这才是“可靠发布订阅”的落地方式。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 发消息只用一次
XADD stream_name * field value,所有组都能看到 - 每个组用
XREADGROUP GROUP group-name consumer-1 COUNT 10 BLOCK 5000 STREAMS stream_name >——>表示“只读新消息”,自动更新组内游标 - 消费成功后必须显式
XACK stream_name group-name id1 id2,否则消息会留在 PEL(Pending Entries List)里,下次还能捞到 - 如果消费者崩溃,未
ACK的消息会在 PEL 中保留,其他同组消费者可用XCLAIM接管
容易踩的坑:消费者组名、消费者名、ID 写错就全乱套
Stream 对名字大小写敏感,且组初始化有隐含逻辑,错一步就卡住:
- 第一次用
XREADGROUP读某个不存在的组,Redis 不会自动创建,必须先XGROUP CREATE stream_name group-name $($表示从最新消息开始) -
consumer-name在组内必须唯一,重复名字会导致消息被覆盖或丢弃(不是报错,而是行为异常) -
XREADGROUP的>只对新消息有效;如果想重放历史,得指定具体 ID,比如0-0,但要注意该 ID 必须存在且未被DEL过 - Stream 默认无限增长,不设
MAXLEN或MINID,磁盘可能被撑爆——尤其日志类场景
真正麻烦的不是命令怎么写,而是“谁负责建组、谁负责清理 PEL、谁监控游标滞后”。这些逻辑不在 Redis 里,得在应用层兜底。Stream 提供了可靠基座,但不替你做运维判断。










