Redis深度历险-Redis Stream

本文大部分内容引自《Redis深度历险:核心原理和应用实践》,感谢作者!!!

Redis Stream

Redis5.0多出了新的数据结构Stream,它是一个新的强大的支持多播的可持久化的消息队列,Redis Stream 狠狠地借鉴了 Kafka 的设计

1、Redis Stream是一个消息链表,其中的每一条消息都有一个唯一的ID和对应的内容,消息是持久化的;每个Stream都有唯一的名称,Redis的key就是Stream的名称;首次使用xadd指令追加消息时会自动创建Stream

2、每个Stream都可以绑定多个消费子,每个消费组都会有一个游标last_delivered_id在Stream数组之上往前移动,表示消费组当前消费到哪条消息了;每个消费组都有一个Stream内唯一的名称,消费组需要用xgroup create进行创建,并不会自动创建消费组;而且消费组消费需要指定从Stream的某个ID进行消费,这个ID用来初始化last_delivered_id变量

3、不同消费组(Consumer Group)之间的状态是相互独立的,互相不受影响,同一份Stream内部的消息会被每个消费组都消费到;但是每个消费组内部的消费者(Consumer)是竞争关系,任意一个消费者读取了消息都会使游标last_delivered_id往前移动,每个消费者都有一个组内唯一名称

4、消费者内部会有一个状态变量pending_ids,记录了当前被客户端(消费者)读取到但未被ack的消息;如果客户端一直不去ack,pending_ids里面的消息会越来越多,消息被ack就会开始减少;pending_ids在Redis官方被称为PEL,也就是Pending Entries List,这是一个很核心的用来确保客户端至少消费了消息一次而不会在网络传输中途丢了消息未处理的核心数据结构

消息ID

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

消息内容

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

增删改查操作

1、xadd追加消息

2、xdel删除消息,这里的删除只是设置了标志位表示了消息是被删除的状态,不影响消息的总长度

3、xrange获取未被删除的消息列表

4、xlen消息长度

5、del删除Stream,整个消息队列

# * 号表示服务器自动生成 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) "xiaoyu"
    3) "age"
    4) "29"
127.0.0.1:6379> xdel codehole 1527849609889-0
(integer) 1
# 长度不受影响
127.0.0.1:6379> xlen codehole
(integer) 3
# 被删除的消息没了
127.0.0.1:6379> xrange codehole - +
1) 1) 1527849629172-0
    2) 1) "name"
    2) "xiaoyu"
    3) "age"
    4) "29"
2) 1) 1527849637634-0
    2) 1) "name"
    2) "xiaoqian"
    3) "age"
    4) "1"
# 删除整个 Stream
127.0.0.1:6379> del codehole
(integer) 1

独立消费

不定义消费组时对Stream进行独立消费,当Stream没有新消息时可以阻塞等待;Redis设计了一个单独消费的指令xread可以将Stream当成普通的消息队列list)来使用;使用xread时可以完全忽略消费组(Consumer Group)的存在,把Stream当成一个普通的列表(list)

# 从 Stream 头部读取两条消息
127.0.0.1:6379> xread count 2 streams codehole 0-0
1) 1) "codehole"
    2) 1) 1) 1527851486781-0
        2) 1) "name"
        2) "laoqian"
        3) "age"
        4) "30"
    2) 1) 1527851493405-0
        2) 1) "name"
            2) "yurui"
            3) "age"
            4) "29"
# 从 Stream 尾部读取一条消息,毫无疑问,这里不会返回任何消息
127.0.0.1:6379> xread count 1 streams codehole $
(nil)
# 从尾部阻塞等待新消息到来,下面的指令会堵住,直到新消息到来
127.0.0.1:6379> xread block 0 count 1 streams codehole $
# 我们从新打开一个窗口,在这个窗口往 Stream 里塞消息
127.0.0.1:6379> xadd codehole * name youming age 60
1527852774092-0
# 再切换到前面的窗口,我们可以看到阻塞解除了,返回了新的消息内容
# 而且还显示了一个等待时间,这里我们等待了 93s
127.0.0.1:6379> xread block 0 count 1 streams codehole $
1) 1) "codehole"
    2) 1) 1) 1527852774092-0
        2) 1) "name"
            2) "youming"
            3) "age"
            4) "60"
(93.11s)
xread count [num] streams codehole [startindex]-[endindex] #在startindex和endindex之间读取num条消息,endindex可选

客户端如果想使用xread进行顺序消费需要记住当前消费到的消息ID,下次调用xread时将上次返回的最后一个消息ID作为参数传入就可以继续消费后续的消息

 

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

127.0.0.1:6379> xread block 1000 count 1 streams codehole $
(nil)
(1.07s)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值