Redis Pub/Sub 与 Stream 在消息可靠性上的区别是什么?

文章导读
Redis Pub/Sub 是无存储的实时广播机制,消息断连即丢;Stream 是带 ACK 的持久化消息队列,支持回溯、消费者组和精确控制。若业务允许消息丢失且追求极低延迟,选 Pub/Sub;若需确保消息必达且可重试,选 Stream。
📋 目录
  1. 命令速用版
  2. 为什么会这样
  3. 分步处理
  4. 怎么验证是否生效
  5. 常见坑
  6. 常见问题
  7. 参考来源
A A

Redis Pub/Sub 是无存储的实时广播机制,消息断连即丢;Stream 是带 ACK 的持久化消息队列,支持回溯、消费者组和精确控制。若业务允许消息丢失且追求极低延迟,选 Pub/Sub;若需确保消息必达且可重试,选 Stream。

先说结论:Pub/Sub 适合实时通知,Stream 适合可靠任务队列,两者不是替代关系而是场景互补。

  • 适合:实时性压倒一切且允许丢失选 Pub/Sub,要求消息不丢且可回溯选 Stream。
  • 重点看:Stream 必须显式管理消费者组(XGROUP)和消息确认(XACK)。
  • 别忽略:Pub/Sub 订阅者离线期间消息彻底消失,无法通过重启恢复。

命令速用版

Pub/Sub 模式仅需发布和订阅命令,Stream 模式需管理消息 ID 和确认状态。

# Pub/Sub 发布与订阅
PUBLISH channel_name "message"
SUBSCRIBE channel_name

# Stream 生产与消费
XADD mystream * field1 value1
XGROUP CREATE mystream mygroup 0
XREADGROUP GROUP mygroup consumer1 COUNT 1 BLOCK 5000 STREAMS mystream >
XACK mystream mygroup 1743405096987-0

为什么会这样

Pub/Sub 是无状态代理,Stream 是独立数据结构。Pub/Sub 消息仅在发布瞬间存在于内存通道,无订阅者则直接丢弃,不写 AOF 也不进 RDB。Stream 消息持久化在内存链表中,每个消息有唯一 ID(时间戳 + 序列),支持按范围查询和重复读取。

Stream 的可靠性依赖消费者组机制,消息读取后进入 Pending Entries List(PEL),只有显式发送 XACK 才会移除。若消费者宕机未确认,消息会保留在 PEL 中,其他消费者可通过 XPCLAIM 接管,实现故障转移。

分步处理

根据可靠性需求选择模式,并配置相应的持久化与确认策略。

1. 评估丢失容忍度
若消息丢失不影响业务(如在线人数广播、开发环境日志),使用 Pub/Sub。若消息丢失会导致数据不一致(如订单处理、支付通知),必须使用 Stream。

2. 配置 Stream 消费者组
创建消费者组时指定起始 ID,0 表示从头开始,$ 表示从新消息开始。生产环境建议使用 0 确保历史消息不丢失,配合 XACK 确保至少一次消费。

3. 管理内存占用
Stream 消息默认不自动删除,需在 XADD 时使用 MAXLEN 参数限制最大长度,或定期调用 XTRIM 清理旧消息,防止内存溢出。

怎么验证是否生效

通过模拟断连和检查 pending 列表来验证可靠性机制。

1. 验证 Pub/Sub 丢失
启动订阅者后断开网络,期间发布者发送消息,重连后订阅者无法收到断连期间的消息,证明无持久化。

Redis Pub/Sub 与 Stream 在消息可靠性上的区别是什么?

2. 验证 Stream 重投
消费者读取消息后不发送 XACK 直接宕机,重启新消费者读取同一组,消息会再次出现,证明 PEL 机制生效。

3. 检查 Pending 列表
使用 XPENDING mystream mygroup 查看未确认消息数量,若数量持续增长说明消费逻辑未正确调用 XACK。

常见坑

忽略 Stream 的确认机制会导致内存泄漏,误用 Pub/Sub 做关键业务会导致数据丢失。

1. 忘记 XACK
不调 XACK 的后果不是消息重复,而是 PEL 不断膨胀,最终拖慢整个 Stream 的读取性能并占用大量内存。

2. 误用 Pub/Sub 做队列
Pub/Sub 所有订阅者都会收到相同消息,无法实现负载均衡,且消费者重启后无法补发离线消息。

3. Stream ID 误解
Stream 消息 ID 是 millisecondsTime-sequence 格式,不能自定义业务主键,填错会直接报错 ERR Invalid stream ID。

常见问题

Pub/Sub 消息能持久化吗?

不能。Pub/Sub 消息不写 AOF 不进 RDB,纯内存一闪而过,订阅者离线即丢失。

Stream 消费者宕机怎么办?

消息会留在 Pending 列表中,其他消费者可通过 XPCLAIM 接管超时消息,实现故障转移。

哪个性能更高?

Pub/Sub 更轻量,吞吐量更高;Stream 因持久化和 ACK 机制,CPU 和内存占用更高,延迟略高但仍为毫秒级。

参考来源

  • Redis 5.0 中 Stream 与 Pub/Sub 有什么核心区别_深度剖析消息传递架构差异
  • 硬核| Redis 消息队列深度实战:从 Pub/Sub 到 Stream,一文打尽所有通信
  • Redis 消息队列:Pub/Sub 与 Stream 对比
  • 性能比拼:Redis Streams vs Pub/Sub
  • 深入解析 Redis 消息队列:三种实现方式的优劣与实践