Redis数据类型:Stream详解

用过Redis做消息队列的都了解,基于Reids的消息队列实现有很多种,例如:

PUB/SUB,订阅/发布模式

但是发布订阅模式是无法持久化的,如果出现网络断开、Redis 宕机等,消息就会被丢弃;

基于List LPUSH+BRPOP或者基于Sorted-Set的实现

支持了持久化,但是不支持多播,分组消费等

为什么上面的结构无法满足广泛的MQ场景? 这里便引出一个核心的问题:如果我们期望设计一种数据结构来实现消息队列,最重要的就是要理解设计一个消息队列需要考虑什么?初步的我们很容易想到

消息的生产

消息的消费

单播和多播(多对多)

阻塞和非阻塞读取

消息有序性

消息的持久化

Stream详解

Stream的结构设计

生产和消费

基本的增删查改

单一消费者的消费

消费组的消费

监控状态

Stream的结构

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

Consumer Group :消费组,使用 XGROUP CREATE 命令创建,一个消费组有多个消费者(Consumer), 这些消费者之间是竞争关系。

last_delivered_id :游标,每个消费组会有个游标 last_delivered_id,任意一个消费者读取了消息都会使游标 last_delivered_id 往前移动。

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

此外我们还需要理解两点:

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

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

​​增删改查

消息队列相关命令:

XADD - 添加消息到末尾

XTRIM - 对流进行修剪,限制长度

XDEL - 删除消息

XLEN - 获取流包含的元素数量,即消息长度

XRANGE - 获取消息列表,会自动过滤已经删除的消息

XREVRANGE - 反向获取消息列表,ID 从大到小

XREAD - 以阻塞或非阻塞方式获取消息列表