文章目录

  • stream
  • Stream基本概念
  • 消息id
  • 消息内容
  • 增删查改
  • 消息生产
  • 添加消息 xadd
  • 查看消息长度 xlen
  • 限制stream最大长度
  • 1.xadd 中添加**maxlen**:
  • 2.xtrim
  • 查询消息 xrange
  • 正向排序:消费id从小到大排
  • 反向查询:消费id从大到小排
  • 删除消息
  • 消息消费
  • 独立消费 xread
  • 消费组
  • stream中出现很多特殊Ids解释
  • 创建消费组
  • 消息消费
  • 查看stream信息
  • 场景问题


stream

Stream基本概念

Redis 5.0 被作者 Antirez 突然发布出来,增加了很多新的特色功能,其最大的新特性就是多出了一个数据结构 Stream,它是一个新的强大的支持多播的可持久化消息队列,作者坦言 Redis Stream 极大地借鉴了 Kafka 的设计。

Redis Stream 的结构如图:

Stream数据类型 redis redis stream 原理_Redis


它有一个消息链表,将所有加入的消息都串起来,每个消息都有一个唯一的 ID 和对应的内容。消息是持久化的,Redis 重启后,内容还在。

每个 Stream 都有唯一的名称,它就是 Redis 的 Key,在首次使用 xadd 执行追加消息时自动创建。

每个 Stream 都可以挂多个消费组(Consumer Group),每个消费组会有个游标 last_delivered_id 在 Stream 数组之上往前移动表示当前消费组已经消费到哪条消息了。每个消费组都有一个 Stream 内唯一的名称,消费组不会自动创建,它需要单独的指令 xgroup create 进行创建,需要指定从 Stream 的某个消息 ID 开始消费,这个 ID 用来初始化 last_delivered_id 变量。

每个消费组的状态都是独立的,相互不受影响。也就是说同一份 Stream 内部的消息会被每个消费组都消费到

同一个消费组可以挂接多个消费者(Consumer),这些消费者之间是竞争关系,任意一个消费者读取了消息都会使游标 last_delivered_id 往前移动。每个消费者有一个组内唯一名称。

消费者内部会有一个状态变量 pending_ids,它记录了当前已经被客户端读取,但是还没有 ack 的消息。如果客户端没有 ack,这个变量里面的消息 ID 就会越来越多,一旦某个消息被 ack,它就开始减少。这个 pending_ids 变量在 Redis 官方被称为 PEL,也就是 Pending Entries List,这是一个核心的数据结构,它用来确保客户端至少消费了消息一次,而不会在网络传输的中途丢失了而没被处理。

消息id

消息 ID 的形式是 TimestampInMillis-sequence,例如 1527846880572-5,它表示当前的消息再毫秒时间戳 1527846880572 时产生,并且是该毫秒内产生的第 5 条消息。消息 ID 可以由服务器自动生成,也可以由客户端自己指定,但是形式必须是 “整数-整数”,而且后面加入的消息的 ID 必须要大于前面的消息 ID。

消息内容

消息内容就是键值对,形如 hash 结构的键值对,这没什么特别之处。

增删查改

增删改查指令说明如下:

1)xadd:向 Stream 追加消息。

2)xdel:向 Stream 中删除消息,这里的删除仅仅是设置标志位,不影响消息总长度。

3)xrange:获取 Stream 中的消息列表,会自动过滤已经删除的消息。

4)xlen:获取 Stream 消息长度。

5)del:删除整个 Stream 消息列表的所有消息。

消息生产

添加消息 xadd

语法:xadd stream_name Id field value(field value)
记住stream中存储的消息必须是kv类型,不允许是单个String,如下操作都是键值对存储的
使用:

xadd news_live * "2020-08-21 10:20" "国航CA1704航班遇颠簸下降千米,业内人士解释:正常操作 "

xadd news_live * "2020-08-21 04:12" "5G成电信业务增长“动力担当” "

*:表示由redis自己生成key,key是由当前时间戳(ms)-0格式

查看消息长度 xlen

语法:*xlen stream_name *

使用:xlen news_live

Stream数据类型 redis redis stream 原理_Redis_02


添加成功后会显示字符串1597979205554-0,改字符串表示时间戳(毫秒)+计数,有点类似于雪花算法

限制stream最大长度

1.xadd 中添加maxlen:

最多存储消息数,依据FIFO原则,自动删除超过最长长度的消息

语法:xadd stream_name maxlen n id field value(field,value)

记住:每次生成消息都需要带这个参数,如果maxlen不带等于没有限制,支持动态改变maxlen

使用:

Stream数据类型 redis redis stream 原理_客户端_03


图片最多存储3条,每次添加xlen一直是3条

疑问:
1.如果我不知道消息具体的大小,我又如何利用maxlen达到自动删除?

解决:在MAXLEN选项个实际技术之间的~参数意味着:我并不真的需要这恰好1000个项目,它可以是1000或1010或1030,只需确保至少保存1000个项目。使用此参数,仅在我们可以删除整个节点时执行修剪。这使它更有效率,通常是你想要的。

Stream数据类型 redis redis stream 原理_客户端_04

2.每次创建消息的时候都需要带上比较麻烦,有没有什么更好的办法?

maxlen,,当然有了,xtrim!!!

2.xtrim

XTRIM命令,它执行与上面的MAXLEN选项非常相似的操作,但是此命令不需要添加任何内容,可以以独立方式对任何Stream运行。
XTRIM mystream MAXLEN 10
XTRIM mystream MAXLEN ~ 10

查询消息 xrange

查询是生产者查询自己生产的消息,和消费者的消费不是一回事

正向排序:消费id从小到大排

1.查询所有消息:xrange stream_name - +

使用:xrange news_live - +

Stream数据类型 redis redis stream 原理_客户端_05


2.指定起始id查询:xrange news_live 1597980701728-0 +

查询的消息id >= 起始id

Stream数据类型 redis redis stream 原理_Stream数据类型 redis_06


3.指定最大id查询:xrange news_live 1597980701728-0 +

查询的消息id <= 结束id

反向查询:消费id从大到小排

1.查询所有消息:srevrange stream_name + -
2.指定起始id查询: xrevrange news + 2
消息id >= 2 倒排
3.指定最大id查询: xrevrange news 2 -
消息id <= 2 倒排

练习命令:

Stream数据类型 redis redis stream 原理_客户端_07

删除消息

语法:xdel stream_name id

Stream数据类型 redis redis stream 原理_客户端_08

消息消费

独立消费 xread

类似于List,生产者往list中写数据,消费者从list中读数据,只能有一个消费者

Stream数据类型 redis redis stream 原理_客户端_09

1.头部读取 0-0
语法:xread count n stream stream_name 0-0

记住:0-0表示从头开启读取数据,这里数据消费记录不会保存,每次都是从头开始,如果接着消费必须自己制定其实id

制定起始id读取:xread count n stream stream_name id

Stream数据类型 redis redis stream 原理_客户端_10

2.尾部读取最新消息 $

从尾部读取最新的一条消息

语法:
1.xread count n streams stream_name $
此时默认不返回任何消息 ???用途

2.xread block time count n streams stream_name $

time为ms,如果time=0表示一直阻塞

Stream数据类型 redis redis stream 原理_Stream数据类型 redis_11


切记:客户端如果想要使用 xread 进行顺序消费,那么一定要记住当前消费到了那里,也就是返回的消息 ID。下次继续调用 xread 时,将上次返回的最后一个消息 ID 作为参数传递过去,就可以继续消费后续的消息。

block 0 表示永远阻塞,直到消息到来;block 1000 表示阻塞 1s,如果 1s 内没有任何消息到来,就返回 nil。

消费组

Stream数据类型 redis redis stream 原理_Redis_12

stream中出现很多特殊Ids解释

  1. “-”:xrange中使用,等同于 小于某个id作用 标识最小id
  2. “+”:xrange中使用,等同于 大于某个id作用 标识最大id
  3. “$”:在给定Stream中已经包含的最大ID,在xread、xcreategroup中标识消费着只能消费最新消息
  4. “>”:在消费者组的上下文中使用,在xread、xreadgroup总标识消费未消费过的消息
  5. “*”:只能与XADD命令一起使用,意味新创建消息自动由redis生成ID。
  6. “0-0”:表示id从0开始读取,xcreategroup标识消费组从id为0开始读取
  7. “0”:表示id从0开始读取,xreadgroup标识消费组消费所有stream中的数据

创建消费组

语法: xgroup create stream_name group_name last_delivered_id

解释:last_delivered_id为0-0 表示从头开始消费,last_delivered_id为 $ 表示从尾部开始消费,只接收新消息,当前stream消息全部忽略

使用:xgroup create news goup1 0-0

Stream数据类型 redis redis stream 原理_数据_13


注意:xread、xreadgroup中都可以加上 block指令,标识阻塞等待,直到接受到新的消息或者等待超时

消息消费

语法:xreadgroup group group_name consumer_name count n streams news ids
注意:ids不理解可以看上面的stream中出现很多特殊Ids解释,没有加count标识消费所有的消息

解释:
1.xreadgroup group group_name consumer_name count n streams stream_name >
消费组开始消费未消费的数据

2.xreadgroup group group_name consumer_name count n streams stream_name 0
表示id从0开始消费,意味着消息stream中保留的所有消息,包括已经消费过的

使用:

1.xreadgroup group goup1 consumer1 streams news >

Stream数据类型 redis redis stream 原理_Stream数据类型 redis_14


2.xreadgroup count 0 group gb c1 streams news 0使用注意

xgroup create news gb 0-0
xreadgroup count 0 group gb c1 streams news 0
xreadgroup count 0 group gb c1 streams news >
xreadgroup count 0 group gb c1 streams news 0

第一次xreadgroup 0无法查询到数据,知道 > 消费完以后,xreadgroup 0才能获取到数据,说明该指令获取消费组中消费者为c1已经消息过的数据,如果把消费者c1改成其他值返回无数据。

使用注意:
1.xcreategroup指定ids如果为$,如果xreadgroup ids利用>、0未消费数据、无法读取之前历史,只能读取最新数据
2.xcreategroup指定ids为0-0,则xreadgroup ids利用>、0等都可使用

查看stream信息

1.xinfo stream stream_name

Stream数据类型 redis redis stream 原理_客户端_15

2.xinfo groups stream_name

Stream数据类型 redis redis stream 原理_客户端_16

场景问题

1.Stream消息太多时怎么办?

2.ack作用,如果忘记ack会怎样?

3.PEL 如何避免消息丢失?