Redis‑Stream 消息队列
Redis5.0 新增 Stream 类型,是 Redis 功能最完整的消息队列,黑马点评秒杀模块用来实现异步订单处理。
1. 基础概念
- 消息 Entry :队列里每一条消息,是 key‑value 键值对;每条消息拥有唯一 ID,格式
时间戳‑自增序号,*让 Redis 自动生成 ID。 - XADD :发送消息命令。
NOMKSTREAM:队列不存在不自动创建,默认不加参数就是自动创建队列MAXLEN:限制队列保存消息最大数量,防止内存无限膨胀
示例业务场景
秒杀业务:用户抢到优惠券,生产者XADD把订单信息丢进 Stream 队列,主线程直接返回给用户 "排队中",消费者后台慢慢处理数据库订单。
2. 两种读取方式对比
方式① XREAD(普通读取,无消费者组)
特点: ✅消息可回溯、支持阻塞等待、一条消息可以被多个消费者重复读取 ❌没有 ACK 确认机制,存在漏读风险
坑点:起始 ID 写
$代表只读取最新消息;处理消息期间来了多条新消息,中间消息直接丢掉,发生漏读。 适合:简单广播场景,允许消息丢失。
方式② XREADGROUP(消费者组读取,生产推荐)
消费者组:一组消费者共同消费同一个队列,三大核心特性
- 消息分流 :同组多个消费者,消息分摊给不同消费者,并行消费提升速度;一条消息只会交给组内一个消费者。不同消费组之间互不干扰,可以重复消费同一条消息。
- 消费偏移记录:组内记录已经处理到哪条消息;服务宕机重启,从上次位置继续读消息,不会丢消息。
- Pending‑List(待确认列表) 消费者拿到消息,消息进入 pending‑list;业务处理完成,必须手动
XACK确认。
- 没 ACK:消息留在 pending‑list,代表未处理完成;
- 业务异常 / 消费者宕机:重启后,能重新读取 pending‑list 里未确认消息,保证消息至少被消费一次。
特殊 ID 符号:
>:读取还没被消费过的新消息(日常监听用)0:读取 pending‑list 中未 ACK 的旧消息(异常恢复、重试用)$:队列最新消息0:队列第一条消息
NOACK 参数:拿到消息自动确认,不进 pending‑list,异常会丢消息,业务不要随便开启。
消费者组相关命令
XGROUP CREATE:创建消费组,MKSTREAM队列不存在就自动创建队列XGROUP DESTORY:删除消费组XGROUP DELCONSUMER:删除组内某个消费者
消费者监听逻辑流程(面试口述)
- while 死循环,XREADGROUP 阻塞监听新消息,ID 传
> - 拿到消息执行业务逻辑,处理成功执行 XACK 确认消息
- 如果业务抛出异常:停止读取新消息,专门读取 pending‑list 里面未确认的消息,进行重试;
- 重试依然失败,记录日志,避免无限死循环。
3.Redis 三种消息队列完整对比表
表格
| 特性 | List(LPOP/BRPOP) | Pub/Sub 发布订阅 | Stream |
|---|---|---|---|
| 消息持久化 | ✅支持 | ❌不支持,下线消息直接丢 | ✅支持 |
| 阻塞读取 | ✅BRPOP 阻塞 | ✅SUBSCRIBE 阻塞 | ✅BLOCK 阻塞 |
| 消息堆积 | 受内存限制;多消费者可以分流消费 | 缓冲区有限,消费者慢直接丢消息 | 队列可限制长度;消费组多消费者并行,缓解堆积 |
| ACK 确认机制 | ❌无,弹出即删除 | ❌无 | ✅pending‑list + XACK 确认 |
| 消息回溯 | ❌读完直接消失,不能重读 | ❌断开就丢失历史消息 | ✅支持,可读取历史消息 |