02.6 - Stream 消息队列
定位: Redis 5.0 引入的消息队列类型——支持消费者组、消息持久化、ACK 确认 面试高频度: ⭐⭐⭐ 考查方式: 消费组模型、消息 ID、List vs Stream 对比、ACK 机制
一、这是什么?为什么需要它?
是什么
Redis Stream 是一个仅追加(append-only)的日志数据结构,每条消息有唯一的 ID,支持多消费者、消费者组、消息确认。
为什么需要 Stream?
为什么有了 List、Pub/Sub 还需要 Stream?
List(BRPOP/LPUSH)的缺陷:
✓ 简单的生产消费者
✗ 无法多播(同一条消息给多个消费者)
✗ 无消息 ID(ack 靠业务自己)
✗ BPOP 是"抢"模式,不是"订阅"模式
Pub/Sub 的缺陷:
✓ 支持多播
✗ 消息不持久——客户端断开则丢失
✗ 无 ACK 机制
Kafka 过于重:
✓ 功能完整
✗ 需要搭建 Kafka 集群
✗ 引入 ZK/KRaft 等依赖
Stream 的定位:
✓ 持久化(基于 RDB/AOF)
✓ 消费者组(负载均衡消费)
✓ 消息 ID + ACK 机制
✓ 轻量级——内嵌在 Redis 中
它们的关系:
简单队列 → List
广播通知 → Pub/Sub
可靠消息 → Stream二、原理拆解
2.1 核心概念
2.2 消息 ID 设计
2.3 消费者组工作机制
2.4 底层存储(Rax——基数树)
三、图解全景
四、实战验证
4.1 基本生产消费
bash
redis-cli
# 1. 生产者:添加消息
127.0.0.1:6379> XADD mystream * name "Alice" action "login"
"1678901234567-0"
127.0.0.1:6379> XADD mystream * name "Bob" action "logout"
"1678901234568-0"
# 2. 消费者:读取消息(非阻塞)
127.0.0.1:6379> XRANGE mystream - + # 所有消息
1) 1) "1678901234567-0"
2) 1) "name"
2) "Alice"
3) "action"
4) "login"
2) 1) "1678901234568-0"
2) 1) "name"
2) "Bob"
3) "action"
4) "logout"
# 3. 阻塞读取(从最新开始等)
127.0.0.1:6379> XREAD COUNT 10 BLOCK 5000 STREAMS mystream $
# 等待 5 秒,有消息则返回
# 4. 按 ID 范围读取
127.0.0.1:6379> XRANGE mystream "1678901234567" +4.2 消费者组
bash
# 创建消费组
redis-cli XGROUP CREATE mystream mygroup $ # 从最新开始
# 或
redis-cli XGROUP CREATE mystream mygroup 0-0 # 从头开始
# 消费者1 读取
redis-cli XREADGROUP GROUP mygroup consumer1 COUNT 1 STREAMS mystream >
# > = 给这个消费者分配未读取的消息
# 消费者2 读取
redis-cli XREADGROUP GROUP mygroup consumer2 COUNT 1 STREAMS mystream >
# ACK
redis-cli XACK mystream mygroup "1678901234567-0"
# 查看 PEL(未确认的消息)
redis-cli XPENDING mystream mygroup
# 查看所有消费者
redis-cli XINFO CONSUMERS mystream mygroup4.3 Stream vs List 性能对比
bash
# Stream 生产测试
redis-benchmark -n 100000 "XADD mystream * msg hello" -q
# ~110000 条/秒
# List 生产测试(同等操作)
redis-benchmark -n 100000 "LPUSH mylist hello" -q
# ~120000 条/秒
# 结论:Stream 的性能不低于 List,功能更丰富五、面试视角
| 追问 | 答案要点 |
|---|---|
| Stream 和 List 做消息队列的区别? | List 简单生产消费、无 ACK、无多播;Stream 有消费组、ACK、消息 ID、多播能力 |
| Stream 和 Pub/Sub 的区别? | Pub/Sub 消息不持久、连接断开丢消息;Stream 持久化、有 ACK、可以回溯消费 |
| Stream 的消息 ID 怎么生成? | 格式 时间戳-序号,由 Redis 自动生成或客户端自定义 |
| 消费组中的 PEL 是什么? | Pending Entries List:已投递消费者但未 XACK 的消息列表,用于故障恢复 |
| XREADGROUP 的 > 参数是什么含义? | "给我分配这个组中未被读取的消息",而非指定 ID |
| Stream 的削峰填谷能力? | Stream 可以累积消息(受内存限制),消费慢的生产不受影响;但量超大时建议用 Kafka |
| 什么时候用 Stream 不合适? | 海量消息堆积(远超内存)→ 用 Kafka;不需要持久化→Pub/Sub |
📚 相关链接
- **List 与 Quicklist** — List 做队列与 Stream 的对比
- **Pub/Sub** — 三种消息模式的对比
- ← 返回 **核心数据结构索引**