背景介绍
Stream是Redis 5.0引入的一种新数据类型,可以使我们更好的使用redis当作我们项目的轻量消息中间件,在设计上借鉴了 kafka,引入了消费组等概念,使redis传输的消息更加可靠,可以持久化消息,支持消息的重传,超时等
系统原理
在stream设计中,生产者通过 xadd 命令往stream结构中增加消息,而消费者则可以选择独立消费或者以消费组的方式来进行消费,一个stream中可以挂多个消费组,每个消费组互不干扰
在消费组中,消费者们通过抢占式来进行消费,抢到一个消息last_delivered_id向前移动,待消费完成后通过xack确认消息,可以保证消息被至少消费了一次
默认消息id组成 时间戳-序号
生产者
生产消息
xadd <key> <key-id> [<maxlen> <number>] <k1> <v1> ...
增加消息
- key-id 可以设置为*就会由系统自己生成,也可以自己指定
- maxlen 可以指定stream的长度,超过长度就会将最老的消息删除
- k1 v1 键和值用空格分开,可以指定多个键值对
127.0.0.1:6379[15]> xadd joblist * k4 v4
"1596433000793-0"
xrang <key> <start-id> <end-id>
查询范围内的消息
- start-id 开始的id -表示最小值
- end-id 结束的id +表示最大值
127.0.0.1:6379[15]> xrange joblist - +
1) 1) "1596427698394-0"
2) 1) "k1"
2) "v1"
2) 1) "1596427709961-0"
2) 1) "k2"
2) "v2"
3) 1) "1596432409683-0"
2) 1) "k3"
2) "v3"
4) 1) "1596433000793-0"
2) 1) "k4"
2) "v4"
xlen <key>
获取长度
127.0.0.1:6379[15]> xlen joblist
(integer) 4
xdel <key> <message-id>
删除消息
127.0.0.1:6379[15]> xdel joblist 1596427709961-0
(integer)
这里补充一个知识点,普通的redis结构当长度为0的时候,key也会被回收,但stream结构的长度为0时也不会被回收
消费者
独立消费
xread [<count> <number>]|[<block> <timeout>] STREAMS <key> <last-message-id>
独立消费消息,STREAMS
为必选项,需要放在命令最后
- count number 读取消息数目
- block timeout 阻塞等待时间,超过等待时间就返回nil 单位(毫秒)
当timeout为0代表永远阻塞
- last-message-id 最后的消息id,在此消息id之后的消息才会被读到
$ 代表最后一个消息id
127.0.0.1:6379[15]> xread STREAMS joblist 0
1) 1) "joblist"
2) 1) 1) "1596427698394-0"
2) 1) "k1"
2) "v1"
2) 1) "1596427709961-0"
2) 1) "k2"
2) "v2"
3) 1) "1596432409683-0"
2) 1) "k3"
2) "v3"
消费组消费
xgroup CREATE <key> <group-name> <last-message-id>
创建消费组消费
- last-message-id
0-0 代表第一个消息id , $ 代表最后一个消息id
127.0.0.1:6379[15]> xgroup create joblist g5 0
OK
xreadgroup GROUP <group-name> <consumer-name> [<block> <timeout>]|[<count> <number>] STREAMS <key> <last-message-id>
消费组内消费消息 GROUP
,STREAMS
两个为关键字
- count number 读取消息数目
- block timeout 阻塞等待时间,超过等待时间就返回nil 单位(毫秒)
当timeout为0代表永远阻塞
- last-message-id 如果是特殊字符
>
那就会读取一个消息并将游标向前一位,如果是其他合法数字就会列出你所有读取但没有xack的消息
127.0.0.1:6379[15]> xreadgroup GROUP g1 c4 count 1 STREAMS joblist >
1) 1) "joblist"
2) 1) 1) "1596432409683-0"
2) 1) "k3"
2) "v3"
xack <key> <group-name> <message-id>
确认消息,同一个消费组的消费组将不会再收到这个消息
``
127.0.0.1:6379[15]> xack joblist g1 1596432409683-0
(integer) 1
一个完整的消息周期是生产者通过 xadd 生产消息,消费者通过 xgroup 创建消费组,然后通过 xreadgroup 获取消息,待消费完成后 xack确认消息
补充命令
XPENDING <key> <group-name> <start-id> <end-id> <count> [<consumer-name>]
显示某个消费组当前正在处理的消息
依次是消息id,消费者名称,闲置的毫秒数,消息被读取次数
127.0.0.1:6379[15]> xpending joblist g1 - + 10
1) 1) "1596427698394-0"
2) "c1"
3) (integer) 21234552
4) (integer) 1
2) 1) "1596427709961-0"
2) "c1"
3) (integer) 21234552
4) (integer) 1
3) 1) "1596433000793-0"
2) "c2"
3) (integer) 5743
4) (integer) 1
XCLAIM <key> <group> <consumer> <min-idle-time> <ID-1> <ID-2> ... <ID-N>
指派消息的消费者
127.0.0.1:6379[15]> xclaim joblist g1 c2 100 1596427698394-0
1) (nil)
127.0.0.1:6379[15]> xpending joblist g1 - + 10
1) 1) "1596427698394-0"
2) "c2"
3) (integer) 2368
4) (integer) 3
2) 1) "1596427709961-0"
2) "c2"
3) (integer) 85641
4) (integer) 2
3) 1) "1596433000793-0"
2) "c2"
3) (integer) 625370
4) (integer) 1
xinfo CONSUMERS <key> <group-name>
获取消费组内的消费者信息
依次是 名称,待确认消息数,唯一id
127.0.0.1:6379[15]> xinfo CONSUMERS joblist g1
1) 1) "name"
2) "c1"
3) "pending"
4) (integer) 0
5) "idle"
6) (integer) 230658
2) 1) "name"
2) "c2"
3) "pending"
4) (integer) 3
5) "idle"
6) (integer) 208507
3) 1) "name"
2) "c4"
3) "pending"
4) (integer) 0
5) "idle"
6) (integer) 2590462
xinfo GROUPS <key>
获取消费组信息
依次是名称,消费者数量,待确认消息数量,游标当前消息id
127.0.0.1:6379[15]> xinfo GROUPS joblist
1) 1) "name"
2) "g1"
3) "consumers"
4) (integer) 3
5) "pending"
6) (integer) 3
7) "last-delivered-id"
8) "1596433000793-0"
2) 1) "name"
2) "g2"
3) "consumers"
4) (integer) 2
5) "pending"
6) (integer) 2
7) "last-delivered-id"
8) "1596427709961-0"
xinfo STREAM <key>
依次是长度,编码配置,分组数量,最后生成的消息id,第一个消息,最后一个消息
127.0.0.1:6379[15]> xinfo STREAM joblist
1) "length"
2) (integer) 4
3) "radix-tree-keys"
4) (integer) 1
5) "radix-tree-nodes"
6) (integer) 2
7) "groups"
8) (integer) 6
9) "last-generated-id"
10) "1596452155355-0"
11) "first-entry"
12) 1) "1596433000793-0"
2) 1) "k4"
2) "v4"
13) "last-entry"
14) 1) "1596452155355-0"
2) 1) "k8"
2) "v8"