Redis7系列:Redis Stream 全面解析

1. 核心概念

Redis Stream 是 Redis 5.0 引入的持久化消息队列数据结构,具有以下特性:

  • 有序消息存储 :基于时间戳的全局唯一消息ID(格式:<毫秒时间>-<序列号>
  • 消费者组模式:支持多消费者协同处理消息
  • 数据持久化:依赖 Redis AOF/RDB 机制
  • 内存高效:底层使用紧凑的基数树(Radix Tree)存储

2. 核心命令语法

2.1 添加流信息

bash 复制代码
# 基本写入(自动生成ID)
XADD key [NOMKSTREAM] [MAXLEN | MINID [= | ~] threshold [LIMIT count]] * | id field value [field value ...]

参数解析:

  • key: Stream 的键名。
  • NOMKSTREAM**: 如果 Stream 不存在,不自动创建(默认会自动创建)。
  • MAXLEN*: 限制 Stream 的最大长度(删除旧消息)。
    • MAXLEN ~ threshold: 近似裁剪(性能优化,允许略微超过阈值)。
    • MAXLEN = threshold: 精确裁剪(严格限制长度)。
  • MINID: 删除 ID 小于 threshold 的消息(类似按时间裁剪)。
  • \*|ID:
    • *: 自动生成消息 ID(格式为 <timestamp>-<sequence>,如 1631234567890-0)。
    • 手动指定 ID(需大于已有最大 ID)。
  • field value: 消息的键值对(支持多个字段)。

示例:

shell 复制代码
# 创建my_stream流  自动生成消息ID
xadd my_stream * name zhangsan age 25

> xadd my_stream * name zhangsan age 25
"1741586247360-0"
>

2.2 获取流信息

shell 复制代码
# 从某一个消息ID开始等待消费消息
XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] id [id ...]

参数解析

  • COUNT:返回的消息数量
  • BLOCK:阻塞的时长(ms)。如果为0表示一直阻塞,直到有消息进来。默认不阻塞
  • STREAMS: 关键字(不可省略)
  • key: 队列名称
  • id:消息的ID。等待消费的消息从此ID往后,不包含此ID

示例:

shell 复制代码
# 从流ID【1741586247360-0】开始获取流信息
xread streams my_stream 1741586247360-0


# 再次增加流信息
> xadd my_stream * name lisi age 18
"1741587049777-0"

# 从流ID【1741586247360-0】开始获取流信息
> xread streams my_stream 1741586247360-0
1) 1) "my_stream"
   2) 1) 1) "1741587049777-0"
         2) 1) "name"
            2) "lisi"
            3) "age"
            4) "18"

2.3 流信息管理

shell 复制代码
# 查看消息范围消息ID由小到大
XRANGE my_stream - + COUNT 3
# 查看消息范围消息ID由大到小
XREVRANGE my_stream + - COUNT 3

# 删除特定消息
XDEL mystream 1630000000000-0
  • -:表示最小的流ID
  • +:表示最大的流ID

2.4 作为消息队列的使用

以上分别说明了流的创建、流的等待以及流的管理。很多人把上述的操作看做为消息的操作,严格意义上是不对的。如果作为消息的话2.3 里面对于流的获取就是消息的消费。

我们都知道,消息消费之后是不能被重复获取的。但是上面的操作是可以一直操作的。

可不可以作为消息队列使用呢,当然可以。官方提供了丰富的API。

2.4.1 创建消费者组

shell 复制代码
# 创建消费者组
XGROUP CREATE key group id | $ [MKSTREAM] [ENTRIESREAD entries-read]

参数解析

  • key: 流名称
  • group:消费者组的名称
  • id:初始消费的 ID(0 从头开始,$ 从最新消息开始)。
  • MKSTREAM:如果 Stream 不存在,自动创建。
  • ENTRIESREAD: 高级用法,指定消费者组的初始读取位置(Redis 7.0+)。

案例:

shell 复制代码
# 创建group_01消费者组,并初始化从头开始
xgroup create my_stream group_01 0

> xgroup create my_stream group_01 0
"OK"

2.4.2 消费者组内读取消息

shell 复制代码
XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] [NOACK] STREAMS key [key ...] id [id ...]

参数解析:

  • GROUP : 关键词
  • group: 消费者组名称
  • consumer:消费者名称
  • NOACK:不自动确认消息(需手动调用 XACK),默认自动确认消息,确认后消息被删除,但是流数据还会存在
  • id
    • >: 读取未分配给其他消费者的消息。
    • 0: 读取已分配给当前消费者但未确认的消息(用于重新处理)。

案例:

shell 复制代码
# 创建消费者【my_consumer】消费消息。这时候消息没有被确认。
xreadgroup group group_01 my_consumer streams my_stream >

> xreadgroup group group_01 my_consumer streams my_stream >
1) 1) "my_stream"
   2) 1) 1) "1741586247360-0"
         2) 1) "name"
            2) "zhangsan"
            3) "age"
            4) "25"
      2) 1) "1741587049777-0"
         2) 1) "name"
            2) "lisi"
            3) "age"
            4) "18"

2.4.3 消息的确认

shell 复制代码
XACK key group id [id ...]

参数解析:

  • group :消费者组明
  • id : 消息的ID

案例:

shell 复制代码
# 确认消费组group_01的消息1741587049777-0, 确认后group_01中对应的消息会被清除。但是流中的信息还在。
xack my_stream group_01 1741587049777-0

> xack my_stream group_01 1741587049777-0
(integer) 1

如果Stream中对用的消息被删除,消费者组还会正常消费么? 当然是可以的

3、与消息队列对比

维度 Redis Stream Kafka RabbitMQ
消息持久化 内存存储+可选持久化 磁盘持久化 内存/磁盘
吞吐量 10万+/秒 百万级/秒 5万+/秒
延迟 亚毫秒级 毫秒级 微秒级
消费模式 发布订阅+消费者组 消费者组 Exchange+队列
消息回溯 支持 支持 不支持
集群支持 Redis Cluster 原生分区 镜像队列
适用场景 实时处理、轻量级队列 大数据管道、日志收集 复杂路由、企业级MQ

选型建议

  • 选择 Redis Stream:需要低延迟、简单部署、与Redis生态集成
  • 选择 Kafka:处理海量数据、需要严格顺序保证
  • 选择 RabbitMQ:需要复杂路由规则、死信队列等高级特性

4、监控指标

指标 检查命令 告警阈值
消息积压量 XPENDING mystream group > 1,000
消费者延迟 XINFO CONSUMERS > 60秒
内存使用量 MEMORY USAGE mystream > 80%最大内存
处理失败率 监控XCLAIM/XDEL次数 > 5%/分钟

5、最佳实践

  1. 控制单个Stream的消息量(建议不超过1千万条)
  2. 合理设置MAXLEN防止内存溢出
  3. 消费者处理需实现幂等性
  4. 重要业务建议开启AOF持久化
  5. 定期监控Pending消息数量

适用场景:

  • 实时消息处理(如聊天消息)
  • 事件溯源系统
  • 分布式任务队列
  • 物联网数据管道

不适用的场景:

  • 需要长期存储的海量数据(超过内存容量)
  • 需要复杂消息路由规则的场景
  • 严格的事务性消息处理
相关推荐
sevevty-seven11 分钟前
Spring Boot 自动装配原理详解
java·spring boot·后端
lamdaxu43 分钟前
分布式调用(02)
后端
daiyunchao44 分钟前
让Pomelo支持HTTP协议
后端
芒猿君1 小时前
AQS——同步器框架之源
后端
SaebaRyo1 小时前
手把手教你在网站中启用https和http2
后端·nginx·https
A-Kamen2 小时前
Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现与实战指南
java·spring boot·后端
豆豆酱2 小时前
Transformer结构详解
后端
upsilon2 小时前
golang切片slice
后端·go
狂奔小菜鸡2 小时前
Java运行时数据区
java·jvm·后端
lovebugs2 小时前
Java并发编程之Lock机制:更灵活的线程同步方案
后端·面试