一、Redis Stream 是什么?
-
日志型、持久化、有序、支持多播+ACK的轻量级消息队列,Redis 5.0 引入,底层由 Radix Tree + listpack 实现,单节点可 10w+ TPS。
-
核心角色:消息 ID(时间戳-序号)、Stream 队列、消费者组(Consumer Group)、消费者(Consumer)、PEL(Pending Entry List)。
二、安装与启用
-
版本 ≥ 5.0 即可;7.0+ 增加了 maxmemory-stream 等参数。
-
默认零配置直接用;若需要限制内存/条数,在 redis.conf 加:
bashstream-node-max-bytes 4kb # 每个 listpack 最大尺寸 stream-node-max-entries 100 # 每个 listpack 最多消息数 maxmemory 2gb # 内存上限 maxmemory-policy stream-eviction # 到达上限按 Stream 策略裁剪
重启即可生效。
三、基础命令速查表
| 场景 | 命令示例 |
|---|---|
| 生产 | XADD order * userId 123 money 88.8 |
| 阻塞读(单播) | XREAD COUNT 100 BLOCK 5000 STREAMS order $ |
| 建消费组 | XGROUP CREATE order cg1 $ MKSTREAM |
| 组内读 | XREADGROUP GROUP cg1 c1 COUNT 10 STREAMS order > |
| 确认 | XACK order cg1 171234567890-0 |
| PEL 查看 | XPENDING order cg1 - + 10 |
| 消息修剪 | XTRIM order MAXLEN ~ 10000 |
四、Java 实战(Spring Boot 3.x)
1.依赖
XML
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.发送
java
@Autowired
private RedisTemplate<String,Object> redis;
public void send(Order o){
MapRecord<String,String,String> r = MapRecord.create("order", BeanUtils.toMap(o));
redis.opsForStream().add(r);
}
3.消费(组模式,自动 ACK)
java
@Bean
StreamListenerContainer<String, ObjectRecord<String,String>> container(
RedisConnectionFactory f) {
var opt = StreamListenerContainerOptions.builder()
.pollTimeout(Duration.ofMillis(100))
.targetType(String.class).build();
var c = StreamListenerContainer.create(f, opt);
c.receive(Consumer.from("cg1", "c1"),
StreamOffset.create("order", ReadOffset.lastConsumed()),
rec -> handle(rec.getValue()));
c.start();
return c;
}
五、进阶能力
-
多播 + 竞争消费 每个消费组独立游标;组内竞争,组间广播。
-
PEL 重放 服务宕机重启后,用 XPENDING 取出未 ACK 的 ID,再 XCLAIM 转移或继续处理,保证至少一次。
-
水平扩展 Redis Cluster 下不同 Stream key 落在不同 slot,天然分片;结合 client-side sharding 可横向扩容。
-
内存控制 XTRIM MAXLEN ~ 100000 或 redis.conf 中 stream-node-max-entries 双重控制,防止堆积爆炸。
六、黑科技玩法
-
延迟队列 生产时把"执行时间"放在字段里,消费者轮询 XPENDING + 系统时间,到期再处理;精度 1s 内,无额外延时插件。
-
ID 生成器 利用 XADD 返回的毫秒-序号全局唯一 ID,替代雪花算法,自带时钟回拨保护。
-
事件溯源 / Audit Log 业务增量事件全部 XADD 到一条 Stream,设置 MAXLEN 0(永不删除),配合 RDB/AOF 做时序溯源。
-
轻量 CDC 监听 Binlog → XADD 到 Stream,下游多组消费者(搜索、缓存、统计)各自订阅,替代 Kafka 降低运维成本。
七、常见踩坑
| 坑点 | 现象 | 规避方案 |
|---|---|---|
| 内存暴涨 | 无 MAXLEN 也未配置 stream-eviction | 生产侧 XTRIM 或配置 maxmemory-policy |
| 重复消费 | ACK 前崩溃,PEL 重放 | 业务幂等或幂等键 |
| 消息丢失 | 主节点宕机,未持久化 | 开启 AOF appendfsync everysec + 主从 |
| 集群漂移 | Stream key 哈希槽切换 | 客户端重连 + XREADGROUP 重新绑定 |
| 阻塞超时 | BLOCK 过大导致连接占满 | 控制 COUNT 与线程池大小 |
八、小结
Redis Stream = 高性能 + 低运维 + 足够用的 MQ 语义。 若你的系统 QPS ≤ 10w、消息体量 ≤ 内存、可接受秒级延迟,Stream 就是最轻量、最省钱的消息中间件方案;再往上,再考虑 Kafka、Pulsar 等专业 MQ。