Redis进阶-Stream

Redis Stream 是Redis 5.0引入的新的数据结构,作为消息队列的完善实现,支持多播、持久化。本文详细介绍了Stream的设计初衷、消息ID、消息内容、消费组消费、消息管理和高可用性,以及适用的场景,帮助理解Stream如何解决Redis PUB/SUB和基于List、Sorted-Set的消息队列不足问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么设计Stream

基于Reids的消息队列实现有很多种,例如:

  • PUB/SUB(订阅/发布模式)
    • 但是发布订阅模式是无法持久化的,如果出现网络断开、Redis 宕机等,消息就会被丢弃。
  • 基于 List LPUSH+BRPOP 或者基于 Sorted-Set 的实现
    • 支持了持久化,但是不支持多播,分组消费等。

Redis5.0 中还增加了一个数据结构 Stream,从字面上看是流类型,但其实从功能上看,应该是Redis对消息队列(MQ,Message Queue)的完善实现。

他弥补了 Redis Pub/Sub 不能支持持久化消息的缺陷。

他是一个新的数据结构,他是一个可以支持多播持久化的消息队列。

在这里插入图片描述

从上图看,它将所有加入的消息形成了一个消息链表,每个小小都有一个唯一的ID以及其对应内容,而且消息是持久化的,所以代表了 Redis 重启之后,内容不会消失。

每个 Stream 都有唯一的名称,就是 RedisKey,我们在首次使用 xadd 指令追加消息的时候会自动创建。

每个 Stream 都可以挂多个消费组,每个消费组会有个游标 last_delivered_idStream 数组之上往前移动,表示当前消费组已经消费到哪条消息了。

  • 消费组

每个消费组都有一个 Stream 内唯一的名称,消费组不会自动创建,它需要单独的指令 xgroup create 进行创建,需要指定 从 Stream 的某个消息 ID 开始消费,这个 ID 用来初始化 last_delivered_id 变量。

每个消费组不会互相影响,状态独立,换句话说就是 Stream 内部消息会被每个消费组都消费到。

  • 消费者

然后同一个消费组中有多个消费者,每个消费者有一个组内唯一ID,消费者之间是竞争关系,任意一个消费者读取了消息之后,last_delivered_id 都会往后移动。

消费者内部有个状态变量 pending_ids ,它记录了当前已经被客户端读取的消息但是没有确认(ack)。如果此时客户端没有 确认(ack),那么在这个变量里的消息 ID 会越来越多,一旦某个消息被确认,他才开始减少。

这个 pending_ids 变量官方称之为 PEL(Pending Entries List),一个很核心的数据结构,确保客户端至少消费了一次消息,而不会在网络传输中把没处理过的消息丢失。

消息ID

消息 ID 的形式它是 timestampInMillis-sequence,比如 123132132-21,他表示当前的消息在毫秒时间戳 123132132 产生,并且是该毫秒内的第 21 条消息。

它可以是由服务器自动生成也可是客户端自己指定,但是必须是单调递增。

消息内容

消息内容就是键值对,如 hash 结构的键值对。

基本操作

操作 说明
xadd 追加消息
xdel 删除消息,这里删除时逻辑删除,不影响消息总长度
xrange 获取消息列表,会自动过滤已经删除的消息
xlen 消息长度
del 删除Stream
xrevrange 反向获取消息列表,ID从大到小
xread 以阻塞或非阻塞方式获取消息列表
# * 号表示服务器自动生成 ID,后面顺序跟着一堆 key/value
# 名字叫 laoqian,年龄 30 岁
127.0.0.1:6379> xadd codehole * name laoqian age 30 
1527849609889-0 # 生成的消息 ID
127.0.0.1:6379> xadd codehole * name xiaoyu age 29
1527849629172-0
127.0.0.1:6379> xadd codehole * name xiaoqian age 1
1527849637634-0
127.0.0.1:6379> xlen codehole
(integer) 3
# - 表示最小值 , + 表示最大值
127.0.0.1:6379> xrange codehole - +
127.0.0.1:6379> xrange codehole - +
1) 1) 1527849609889-0
   2) 1) "name"
      2) "laoqian"
      3) "age"
      4) "30"
2) 1) 1527849629172-0
   2) 1) "name"
      2) "xiaoyu"
      3) "age"
      4) "29"
3) 1) 1527849637634-0
   2) 1) "name"
      2) "xiaoqian"
      3) "age"
      4) "1"
# 指定最大消息 ID 的列表
127.0.0.1:6379> xrange codehole - 1527849629172-0
1) 1) 1527849609889-0
   2) 1) "name"
      2) "laoqian"
      3) "age"
      4) "30"
2) 1) 1527849629172-0
   2) 1) "name"
      2)<
<think>好的,用户想了解Redis Stream的使用方法,需要教程或示例代码。首先,我需要回忆一下Redis Stream的基本概念和相关命令。记得Redis StreamRedis 5.0引入的消息队列结构,支持消费者组和持久化。 用户可能希望从基础操作开始,比如如何添加消息、读取消息,然后进阶到消费者组的使用。可能需要分步骤讲解,并附上示例代码,这样用户更容易理解。还要注意引用之前的资料,比如引用[1]和引用[2]提到的特性,比如基数树存储、命令语法等。 先整理核心命令。添加消息用XADD,读取用XREAD,创建消费者组用XGROUP CREATE,消费消息用XREADGROUP。这些是基本操作。示例代码部分可以用Python的redis模块展示,这样用户能直接看到如何应用。 需要确保示例代码正确,比如连接Redis的部分,命令参数是否正确。比如XADD的语法是XADD stream名 * key1 value1 key2 value2,其中*表示自动生成消息ID。在Python中,参数可能需要以字典形式传递。 另外,消费者组的示例要说明如何创建组,如何让不同的消费者读取消息,并处理ACK确认。这部分容易出错,要检查命令参数是否正确,比如消费者组的名称、消费者的名称,以及ACK的机制。 还要考虑用户可能的后续问题,比如性能优化、应用场景,所以在相关问题里可以列出这些,比如如何保证消息可靠性,消费者组如何处理故障,或者如何监控Stream的状态。这些能帮助用户深入理解。 最后,确保回答结构清晰,分步骤讲解,代码示例正确,并且引用标记正确。检查是否有遗漏的重要命令或使用场景,确保覆盖基本使用方法,让用户能够快速上手使用Redis Stream。</think>### Redis Stream 使用教程 #### 一、基础操作 1. **添加消息** ```python import redis r = redis.Redis() # 添加消息(自动生成消息ID) msg_id = r.xadd('mystream', {'field1': 'value1', 'field2': 'value2'}) print(f"消息ID: {msg_id}") # 格式如 1651234567890-0 ``` 2. **读取消息** ```python # 读取最新消息(阻塞式,最多等待5000ms) messages = r.xread({'mystream': '$'}, block=5000, count=1) print("最新消息:", messages) # 读取历史消息(从ID 0开始) messages = r.xread({'mystream': '0'}, count=10) ``` #### 二、消费者组模式 1. **创建消费者组** ```python # 创建消费者组(需指定起始ID) r.xgroup_create('mystream', 'mygroup', id='0') ``` 2. **消费者消费消息** ```python # 消费者A读取未确认消息 messages = r.xreadgroup('mygroup', 'consumerA', {'mystream': '>'}, count=1) # 处理消息后确认 for msg in messages: r.xack('mystream', 'mygroup', msg[1][0][0]) # 参数为消息ID ``` #### 三、高级特性 1. **查看流信息** ```python print(r.xinfo_stream('mystream')) # 包含长度、消费者组数量等 print(r.xinfo_groups('mystream')) # 显示所有消费者组 ``` 2. **消息ID范围查询** ```python # 查询指定ID范围内的消息 messages = r.xrange('mystream', min='1651234567890-0', max='+', count=5) ``` #### 四、Python完整示例 ```python # 生产者 for i in range(3): r.xadd('mystream', {'sensor': f"data{i}", 'ts': str(time.time())}) # 消费者组处理 while True: msgs = r.xreadgroup('mygroup', 'worker1', {'mystream': '>'}, count=1) if not msgs: break for msg in msgs: process_message(msg[1][0][1]) # 自定义处理函数 r.xack('mystream', 'mygroup', msg[1][0][0]) ``` > 注意:Redis Stream底层使用基数树(Radix Tree)存储,内存效率比普通列表高50%以上[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值