【Redis】数据类型:Stream
10.redis流(Stream)
Redis Stream是Redis5.0版本新增加的数据结构。主要用于消息队列(MQ,Message Queue)。
Redis本身就是一个Redis发布订阅(pub/sub),来实现消息队列的功能,但它有个缺点,就是消息无法持久化,如果出现网络断开、Redis宕机等,消息就会被丢弃。
而 Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端,访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。
redis常见数据类型操作命令
官网英文: https://redis.io/commands/
中文:http://www.redis.cn/commands.html
是什么
Redis5.0 之前的痛点,Redis消息队列的2种方案:
(1)List实现消息队列,List实现方式,其实就是点对点的模式
(2)Pub/Sub

Redis5.0版本新增了一个更强大的数据结构---Stream
一句话:Stream流就是Redis版的MQ消息中间件+阻塞队列
能干嘛
实现消息队列,它支持消息的持久化、支持自动生成全局唯一ID、支持ack确认消息的模式、支持消费组模式等,让消息队列更加的稳定和可靠
底层结构和原理说明

一个消息链表,将所有加入的消息都串起来,每个消息都有一个唯一的ID和对应的内容

队列相关指令

1.XADD
添加消息到队列末尾,消息ID必须要比上一个ID大,默认用星号表示自动生成ID;* 用于XADD命令中,让系统自动生成ID;
XADD用于向Stream队列中添加消息,如果指定的Stream队列不存在,则该命令执行时会新建一个Stream队列

生成的消息ID,有两部分组成,毫秒时间戳-该毫秒内产生的第一条消息
* 表示服务器自动生成MessageID(类似MySQL里面主键auto_increment),后面顺序跟着一堆业务key/value
标准语法:
# 自动生成ID(推荐) XADD 队列名 MAXLEN ~ 最大长度 * 键1 值1 键2 值2 ...手动指定ID(不推荐,必须严格遵守规则)
XADD 队列名 ID 键1 值1
关键参数
*:最常用,让 Redis 自动生成唯一消息 ID MAXLEN ~ n:可选,限制队列最大长度,自动淘汰旧消息(节约内存) 消息必须是 成对的 key-value,不能为空
消息 ID 规则
ID 格式
固定格式:时间戳-序列号
时间戳:Redis 服务器本地毫秒数 序列号:同一毫秒内的自增序号,从 0 开始递增
示例:
1745000000000-0 → 第 1 条消息
1745000000000-1 → 同一毫秒的第 2 条消息
1745000000001-0 → 下一毫秒的第 1 条消息
强制约束(Redis 底层保证)
全局单调递增:后一条 ID 一定 > 前一条 ID(Stream 核心特性) 时钟回拨自动修复:服务器时间倒退时,Redis 不会使用更小的时间戳,沿用上一个时间戳,只递增序列号 手动 ID 必须合法:格式必须是 数字-数字,且必须比上一条 ID 大
实操示例
示例 1:自动生成 ID(生产环境标准用法)
# 向 mystream 队列添加消息,自动生成ID
XADD mystream * name 张三 age 20 city 北京
# 再添加一条
XADD mystream * name 李四 age 25 city 上海
返回结果(自动生成的 ID):
1745012345678-0
1745012345679-0
示例 2:限制队列长度(防止内存爆炸)
# 队列最多保留 1000 条消息,满了自动删除旧消息
XADD mystream MAXLEN ~ 1000 * content "订单支付成功"
示例 3:手动指定 ID(仅测试用)
# 手动ID必须大于上一条
XADD mystream 1745012345680-0 content test
2.XRANGE key start end [COUNT count]
用于获取消息列表(可以指定范围),忽略删除的消息
start 表示开始值,-代表最小值
end 表示结束值,+代表最大值
count 表示最多获取多少个值

3.XREVRANGE key end start [COUNT count]
根据ID降序输出

4.XDEL key id [id ...]

5.XLEN key

6.XTRIM key MAXLEN|MINID
用于对Stream的长度进行截取,如超长会进行截取
MAXLEN 允许的最大长度,对流进行修剪限制长度
MINID 允许的最小id,从某个id值开始比该id值小的将会被抛弃

7.XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] id [id ...]
可以读取多个key
用于获取消息(阻塞/非阻塞)
只会返回大于指定ID的消息,COUNT最多读取多少条消息;BLOCK是否以阻塞的方式读取消息,默认不阻塞,如果milliseconds设置为0,表示永远阻塞
非阻塞
$表特殊ID,表示以当前Stream已经存储的最大的ID作为最后一个ID,当前Stream中不存在大于当前最大ID的消息,因此此时返回nil 0-0代表从最小的ID开始获取Stream中的消息,当不指定count,将会返回Stream中的所有消息,注意也可以使用0 (00/000也都是可以的) ![img]()
阻塞

Stream的基础方法,使用XADD存入消息,和XREAD循环阻塞读取消息的方式,可以实现简易版的消息队列

消费组相关指令

XINFO GROUPS 打印消费组的详细信息
XINFO STREAM 打印stream的详细信息
1.XGROUP CREATE key group id|$
用于创建消费组
xgroup create mystream group $
xgroup create mystream groupB 0
$表示从Stream尾部开始消费
0表示从Stream头部开始消费
创建消费组的时候必须指定ID,ID为0表示从头开始消费,为$表示只消费新消息
''
2.XREADGROUP GROUP group [COUNT count] [BLOCK milliseconds] STREAMS key id
">",表示从第一条尚未被消费的消息开始读取

消费组groupA内的消费者consumer1从mystream消息队列中读取所有消息
但是,不同消费组的消费者可以消费同一条消息

消费组的目的?
让组内的多个消费者共同分担读取消息,所以,我们通常会让每个消费者读取部分消息,从而实现消息读取负载在多个消费者间是均衡分部的

重点问题
基于 Stream 实现的消息队列,如何保证消费者在发生故障或宕机再次重启后,仍然可以读取未处理完的消息?
Streams 会自动使用内部队列(也称为 PENDING List)留存消费组里每个消费者读取的消息保底措施,直到消费者使用 XACK命令通知 Streams"消息已经处理完成”。消费确认增加了消息的可靠性,一般在业务处理完成之后,需要执行 XACK 命令确认消息已经被消费完成

3.XPENDING
查询每个消费组内所有消费组[已读取、但尚未确认]的消息

查看某个消费组具体读取了那些数据

4.XACK key group id [id...]
向消息队列确认消息处理已完成

5.XINFO 用于打印Stream\Consumer\Group的详细信息

四个特殊符号
| - + | 最小和最大可能出现的Id |
|---|---|
| $ | $表示只消费新的消息,当前流中最大的Id,可用于将要到来的信息 |
| > | 用于XREADGROUP命令,表示迄今还没有发送给组中使用者的信息,会更新消费者组的最后Id |
| * | 用于XADD命令,让系统自动生成Id |


浙公网安备 33010602011771号