4. 中间件通信模型:发布/订阅模式、列表阻塞弹出、Stream消费者组对比

在Redis缓存异步任务编排场景中,中间件通信模型决定了任务如何从生产者传递到消费者,以及系统在故障时的行为。Redis提供了三种核心通信模型:发布/订阅(Pub/Sub)、列表阻塞弹出(BLPOP/BRPOP)和Stream消费者组。三者在消息可靠性、消费模式、故障恢复能力上存在本质差异。

4.1 发布/订阅模式(Pub/Sub)

Pub/Sub是一种消息广播模型,生产者将消息发送到指定频道,所有订阅该频道的消费者都会收到消息。该模型不持久化消息,消费者必须在线才能接收。

核心特征:
  • 消息即发即弃:消息不写入磁盘,Redis重启后丢失。
  • 消费者离线即丢失:若消费者断开连接,期间发送的消息永久丢失。
  • 无确认机制:生产者无法知道消费者是否成功处理消息。
  • 适用场景:实时通知、日志广播、状态变更推送。
发布/订阅模式(Pub/Sub)通信模型 生产者(Publisher) 频道:task:notify 消费者A(在线) 消费者B(在线) 消费者C(离线) ⚠ 消费者C离线期间,频道中所有消息永久丢失。Pub/Sub无消息积压能力。 消费者A和B同时收到相同消息,实现广播。
故障排查要点:Pub/Sub模式下,若消费者短暂重启或网络闪断,丢失的消息无法追溯。排查时需检查消费者连接状态和频道订阅数,确认是否存在离线窗口。

4.2 列表阻塞弹出模式(BLPOP/BRPOP)

基于Redis List数据结构的阻塞弹出模型,利用BLPOP或BRPOP命令实现可靠的任务队列。消息被持久化在列表中,消费者通过阻塞方式等待新消息,超时后自动返回。

核心特征:
  • 消息持久化:消息存储在List中,Redis重启后不丢失(RDB/AOF)。
  • 至少一次消费:消息弹出后从列表移除,消费者崩溃可能导致消息丢失(需结合备份队列)。
  • 单消费者竞争:多个消费者阻塞在同一List上时,每条消息仅被一个消费者获取。
  • 适用场景:任务队列、延迟任务、异步处理。
列表阻塞弹出模式(BLPOP)通信模型 生产者(LPUSH) Redis List task:queue [msg3] → [msg2] → [msg1] 消费者A(BLPOP) 消费者B(BLPOP) 消费者C(阻塞等待) ⚡ 消息被弹出后从List移除。消费者A和B竞争获取消息,每条消息仅被一个消费者处理。
故障排查要点:BLPOP模式下,若消费者处理消息后崩溃,消息已从List移除,无法重新消费。建议结合备份队列或消息确认机制(如RPOPLPUSH)实现可靠消费。

4.3 Stream消费者组模式

Redis Stream是Redis 5.0引入的持久化消息队列,支持消费者组、消息确认、消息回溯等高级特性。每个消息有唯一ID,消费者组内成员独立消费,支持故障转移和消息重试。

核心特征:
  • 消息持久化:消息存储在Stream中,支持RDB/AOF持久化。
  • 消费者组:组内消息自动负载均衡,每条消息仅被组内一个消费者处理。
  • 消息确认(ACK):消费者处理完成后需显式ACK,未ACK的消息可重新投递。
  • 消息回溯:支持按ID范围读取历史消息,便于故障恢复。
  • 适用场景:任务编排、事件溯源、可靠消息队列。
Stream消费者组模式通信模型 生产者(XADD) Redis Stream task:stream ID: 1700000001-0 → 1700000002-0 消费者组:group1 消费者组:group2 消费者A1 消费者A2 消费者B1 消费者B2(故障) ✅ 消费者B2故障后,其未ACK的消息自动重新分配给组内其他消费者(B1),实现故障转移。

4.4 三种模型对比总结

对比维度 发布/订阅(Pub/Sub) 列表阻塞弹出(BLPOP) Stream消费者组
消息持久化 不持久化 持久化(List) 持久化(Stream)
消息可靠性 无确认,离线丢失 至少一次(弹出即移除) 至少一次(需ACK)
消费模式 广播(所有订阅者) 竞争(单消费者) 组内负载均衡
消息回溯 不支持 不支持 支持(按ID范围)
故障恢复 无 需手动补偿 自动重新投递
适用场景 实时通知、广播 简单任务队列 可靠任务编排、事件溯源

4.5 故障场景与选型建议

常见故障场景:
  • Pub/Sub消息丢失:消费者重启或网络抖动导致消息永久丢失。排查时检查Redis日志中客户端连接事件,确认离线窗口。
  • BLPOP消息重复消费:消费者处理超时导致消息被其他消费者获取,或崩溃后消息丢失。建议使用BRPOPLPUSH实现可靠队列。
  • Stream消费者组消息积压:消费者处理速度跟不上生产速度,导致Stream长度持续增长。需监控Stream长度和消费者待处理消息数。
选型建议:
  • 若任务允许丢失且需要广播,选择Pub/Sub(如状态变更通知)。
  • 若任务需要可靠处理但允许少量丢失,选择BLPOP(如日志处理)。
  • 若任务需要严格可靠性、故障转移和消息回溯,选择Stream消费者组(如任务编排、支付回调)。

4.6 代码示例:Stream消费者组基本使用

// 生产者:添加消息到Stream
XADD task:stream * taskId "1001" status "pending"

// 创建消费者组
XGROUP CREATE task:stream group1 $ MKSTREAM

// 消费者:读取未处理消息
XREADGROUP GROUP group1 consumer1 COUNT 1 BLOCK 5000 STREAMS task:stream >

// 消费者:确认消息处理完成
XACK task:stream group1 1700000001-0

// 查看待处理消息(用于故障排查)
XPENDING task:stream group1 - + 10

Stream消费者组通过消息ID、消费者组和ACK机制,实现了比Pub/Sub和BLPOP更可靠的通信模型,是Redis缓存异步任务编排的首选方案。