PUBLISH和SUBSCRIBE不支持事件过滤、重试、确认或持久化,无法用于复杂事件处理;STREAM才具备消费组、消息ID、ACK机制等可靠特性。

PUBLISH 和 SUBSCRIBE 本身不支持事件过滤、重试、确认或持久化,不能直接用于复杂事件处理。真要落地复杂场景(比如订单状态流转、多服务协同、失败补偿),得绕开纯 Pub/Sub,用 STREAM 或搭配外部组件。
为什么不能靠 SUBSCRIBE 做可靠事件处理?
Pub/Sub 是“发完即忘”:消息只推给当前在线的订阅者,断连就丢,无 ACK、无重放、无消费位点。
常见踩坑现象:
-
SUBSCRIBE连接意外断开后,中间发布的消息彻底丢失 - 多个消费者订阅同一频道,消息被广播给所有人 —— 不是“负载均衡”,而是“重复消费”
-
PUBLISH返回值只是当前活跃订阅者数量,不表示消息是否被成功处理 - 无法按时间/ID回溯历史消息,
PUBSUB命令查不到已发布但无人接收的消息
STREAM 才是复杂事件处理的合理起点
Redis 5.0+ 的 STREAM 提供了消费组(XGROUP)、消息 ID、ACK 机制和挂起列表(XPENDING),这才是能支撑事件溯源、幂等、重试的基础。
关键差异点:
- 消息写入
STREAM后持久存在,即使消费者离线也能后续拉取 -
XREADGROUP支持多消费者分摊同一流,自动分配未处理消息 -
XACK显式标记消息已处理,失败时可从XPENDING拉回重试 -
XCLAIM能把超时未 ACK 的消息转移给其他消费者(防 hang 死)
示例:创建一个带消费组的流
XADD order-events * event_type "payment_succeeded" order_id "12345" XGROUP CREATE order-events mygroup $ MKSTREAM XREADGROUP GROUP mygroup consumer1 COUNT 1 STREAMS order-events >
如果非要沿用 Pub/Sub,必须加一层兜底逻辑
仅限低一致性要求场景(如 UI 实时刷新、监控告警推送),且必须主动规避其缺陷:
- 所有关键事件,先存到
STRING或HASH中(带时间戳和状态),再PUBLISH通知“有新事件”,让下游自己去查详情 - 用
PUBSUB NUMSUB channel定期检查订阅者存活数,为 0 时触发告警 —— 防止整个链路静默中断 - 模式订阅(
PSUBSCRIBE)慎用:匹配规则在服务端展开,高频通配符(如*)可能拖慢 Redis 主线程 - 不要在
SUBSCRIBE回调里做耗时操作(如 DB 写入),否则阻塞连接,导致后续消息积压甚至断连
真正复杂的事件编排,Redis 只能当“信使”
涉及条件分支、等待多个事件、超时控制、事务性补偿时,Redis 本身不提供 DSL 或状态机能力。这时候它更适合做:
- 事件广播通道(
PUBLISH触发外部工作流引擎) - 消费组协调信号(
STREAM+ 外部调度器轮询XPENDING) - 轻量级服务发现心跳(定期
PUBLISH心跳,其他服务SUBSCRIBE监听上线/下线)
最常被忽略的一点:频道名不是路径,也不是命名空间 —— news 和 news.sports 在 Pub/Sub 里完全无关,除非你用 PSUBSCRIBE 显式匹配。想靠点号分层管理,得自己约定并实现解析逻辑,Redis 不帮你做。


















