Redis基本数据结构之Stream

2 Redis Stream

Redis5.0 最大的新特性就是多出了一个数据结构 Stream,它是一个新的强大的支持多播的可持久化的消息队列

stream总述

在这里插入图片描述

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

具体玩法如下

1:每个stream都有唯一的名称,就是key.

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

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

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

每个消费组都有一个Stream 内唯一的名称,消费组不会自动创建,它需要单独的指令xgroup create进行创

建,需要指定从 Stream 的某个消息 ID 开始消费,这个 ID 用来初始化last_delivered_id变量

3:每个消费组(Consumer Group)的状态都是独立的,相互不受影响,

4:同一个消费组 (Consumer Group) 可以挂接多个消费者 (Consumer),这些消费者之间是竞争关系,任意

一个消费者读取了消息都会使游标last_delivered_id往前移动。每个消费者有一个组内唯一名称。

5:消费者 (Consumer) 内部会有个状态变量pending_ids,它记录了当前已经被客户端读取,但是还没有 ack

的消息。如果客户端没有 ack,这个变量里面的消息 ID 会越来越多,一旦某个消息被 ack,它就开始减少。

这个 pending_ids 变量在 Redis 官方被称之为PEL,也就是Pending Entries List,这是一个很核心的数据结

构,它用来确保客户端至少消费了消息一次,而不会在网络传输的中途丢失了没处理。

常用操作的命令

生产端

  1. xadd命令:

在这里插入图片描述
*号表示服务器自动生成 ID,后面顺序跟着一堆 key/value。

1713788135332-0 则是生成的消息 ID,由两部分组成:时间戳-序号。时间戳时毫秒级单位,是生成消息的

Redis服务器时间,它是个64位整型。序号是在这个毫秒时间点内的消息序号。它也是个64位整型。为了保证消息是有序的,因此Redis生成的ID是单调递增有序的。由于ID中包含时间戳部分,为了避免服务器

时间错误而带来的问题(例如服务器时间延后了),Redis的每个Stream类型数据都维护一个

latest_generated_id属性,用于记录最后一个消息的ID。若发现当前时间戳退后(小于latest_generated_id

所记录的),则采用时间戳不变而序号递增的方案来作为新消息ID(这也是序号为什么使用int64的原因,保

证有足够多的的序号),从而保证ID的单调递增性质。

强烈建议使用Redis的方案生成消息ID,因为这种时间戳+序号的单调递增的ID方案,几乎可以满足你全部的

需求。但ID是支持自定义的。

2.xrange命令:获取消息列表,会自动过滤已经删除的消息

xrange stream - + 其中-表示最小值 , + 表示最大值

在这里插入图片描述
del删除Stream (删除整个Stream)
xdel可以删除指定的消息(指定ID)
在这里插入图片描述
消费端

单消费端

虽然Stream中有消费者组的概念,但是可以在不定义消费组的情况下进行 Stream 消息的独立消费,当

Stream 没有新消息时,甚至可以阻塞等待。Redis 设计了一个单独的消费指令xread,可以将 Stream 当成

普通的消息队列 (list) 来使用。使用 xread 时,我们可以完全忽略消费组 (Consumer Group) 的存在,就好

比 Stream 就是一个普通的列表 (list)。

​ xread count 1 streams stream1 0-0 表示从 Stream 头部读取1条消息,0-0指从头开始

在这里插入图片描述

​ xread count 1 streams stream1 $

在这里插入图片描述

$代表从尾部读取,上面的意思就是从尾部读取最新的一条消息,此时默认不返回任何消息

应该以阻塞的方式读取尾部最新的一条消息,直到新的消息的到来

比如如下:

在这里插入图片描述

block0表示一直阻塞

群组消费

创建消费者组

在这里插入图片描述
消费组消费

xreadgroup GROUP c1 consumer1 count 1 streams stream1 >

Stream需要考虑的问题

1:Stream消息太多怎么办?

要是消息积累太多,Stream 的链表岂不是很长,内容会不会爆掉?xdel 指令又不会删除消息,它只是给消息

做了个标志位。Redis 自然考虑到了这一点,所以它提供了一个定长 Stream 功能。在 xadd 的指令提供一个定长长度maxlen,就可以将老的消息干掉,确保最多不超过指定长度。

2:消息如果忘记ACK会怎么样?

Stream 在每个消费者结构中保存了正在处理中的消息 ID 列表 PEL,如果消费者收到了消息处理完了但是没

有回复 ack,就会导致 PEL 列表不断增长,如果有很多消费组的话,那么这个 PEL 占用的内存就会放大。所

以消息要尽可能的快速消费并确认。

3:PEL如何避免消息丢失

在客户端消费者读取 Stream 消息时,Redis 服务器将消息回复给客户端的过程中,客户端突然断开了连

接,消息就丢失了。但是 PEL 里已经保存了发出去的消息 ID。待客户端重新连上之后,可以再次收到 PEL

中的消息 ID 列表。不过此时 xreadgroup 的起始消息 ID 不能为参数>,而必须是任意有效的消息 ID,一般

将参数设为 0-0,表示读取所有的 PEL 消息以及自last_delivered_id之后的新消息。

2.1 Redis中几种消息队列实现的总结

基于List的LPUSH+BRPOP 的实现

足够简单,消费消息的延迟几乎为0,但是需要处理空闲连接的问题

如果线程一直阻塞在那里,Redis客户端的连接就成了闲置连接,闲置过久,服务器一般会主动断开连接,减

少闲置资源占用,这个时候blpop和brpop或抛出异常,所以在编写客户端消费者的时候要小心,如果捕获

到异常,还有重试。

其他缺点包括:
消费组确认ACK比较复杂,不能保证消费组消费消息后是否成功处理的问题。通常需要维护一个Pending列表,保证消息处理确认;不能做广播模式;不能重复消费,一旦消费就会被删除;不支持分组消费

基于Sorted-Set的实现

多用来实现延迟队列,当然也可以实现有序的普通的消息队列,但是消费者无法阻塞的获取消息,只能轮

询,不允许重复消息。

PUB/SUB,订阅/发布模式

优点:典型的广播模式,一个消息可以发布到多个消费者;多信道订阅,消费者可以同时订阅多个信道,从而接收

多类消息;消息即时发送,消息不用等待消费者读取,消费者会自动接收到信道发布的消息。

缺点:消息一旦发布,不能接收。换句话就是发布时若客户端不在线,则消息丢失,不能寻回;不能保证每个消费

者接收的时间是一致的;若消费者客户端出现消息积压,到一定程度,会被强制断开,导致消息意外丢失。

通常发生在消息的生产远大于消费速度时;可见,Pub/Sub 模式不适合做消息存储,消息积压类的业务,而

是擅长处理广播,即时通讯,即时反馈的业务。

基于Stream类型的实现

大体上没问题

  • 29
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redis的list数据结构在不同的版本中有所变化,下面列举了几个主要版本中list数据结构的变化: 1. Redis 1.x版本中的list数据结构:在Redis 1.x版本中,list是由双端链表(adlist)结构实现的。它包含了链表长度、头节点和尾节点等元信息,同时支持在链表的两端进行插入和删除操作。 2. Redis 2.x版本中的list数据结构Redis 2.x版本中对list的实现进行了优化,采用了ziplist(压缩列表)和linkedlist(双端链表)两种结构来实现。具体而言,当list中的元素比较少时,Redis会采用ziplist的方式来存储数据,以节省内存。当list中的元素比较多时,Redis会采用linkedlist的方式来存储数据,以提高性能。 3. Redis 3.x版本中的list数据结构Redis 3.x版本中对list的实现进行了进一步改进,引入了quicklist(快速列表)结构。它是一种由多个ziplist组成的链表结构,用于存储大量的列表数据。quicklist支持快速的插入、删除和查找操作,并且可以按照分片方式进行操作,以提高性能和扩展性。 4. Redis 4.x版本中的list数据结构Redis 4.x版本中对list的实现进行了细节优化,引入了stream(流数据)结构,支持更多的操作和数据类型转换。stream是一种基于list的结构,支持按照时间线进行排序,并可以进行分区、分组等操作,适用于实时数据处理场景。 总之,Redis的list数据结构在不同的版本中有所变化,但都保持了链式存储结构的特点,并且不断引入新的技术和优化方式,以满足不同的业务需求和场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值