Redis Stream 特性是Redis 5.0之后才有的。Redis Stream的主要应用就是时间序列的消息流分发。PUB/SUB也可以做消息流分发,但是PUB/SUB不记录历史消息,而Redis Stream可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。
Redis stream也是有长度大小限制的,超过设置的最大长度,最旧的消息会被丢失
向队列添加消息,同时也创建一个队列
> XADD mystream * sensor-id 1234 temperature 19.8
1518951480106-0
使用XADD创建一个stream的时候,可以设置一个最大长度MAXLEN,由于Redis Sream的内部实现,精确的设置一个长度上限消耗比较大,所以XADD提供了一个模糊设置方式:
> XADD mystream MAXLEN ~ 1000 * sensor-id 1234 temperature 19.8
意思是长度可以超过1000一些,由Redis自己觉得什么时候截断,但是截断以后一定不要小于1000。
下边是对于Stream的一些基本操作:
获取消息队列长度:
> XLEN mystream
(integer) 2
通过ID范围获取消息:
> XRANGE mystream - +
1) 1) 1518951480106-0
2) 1) "sensor-id"
2) "1234"
3) "temperature"
4) "19.8"
通过XREAD获取消息:
> XREAD COUNT 2 STREAMS mystream 0
1) 1) "mystream"
2) 1) 1) 1519073278252-0
2) 1) "foo"
2) "value_1"
2) 1) 1519073279157-0
2) 1) "foo"
2) "value_2"
阻塞的读消息:
> XREAD BLOCK 0 STREAMS mystream $
上述的基本操作都比较自由,可以根据实际需要自己灵活组合使用,但是Redis Stream最重要的也是最常用的一种使用模式是Consumer Group。
在使用consumer group之前应该先了解一些概念:
创建一个Group:
> XGROUP CREATE mystream mygroup $
OK
向队列添加新消息:
> XADD mystream * message apple
1526569495631-0
> XADD mystream * message orange
1526569498055-0
> XADD mystream * message strawberry
1526569506935-0
> XADD mystream * message apricot
1526569535168-0
> XADD mystream * message banana
1526569544280-0
客户端读取消息:
> XREADGROUP GROUP mygroup Alice COUNT 1 STREAMS mystream >
1) 1) "mystream"
2) 1) 1) 1526569495631-0
2) 1) "message"
2) "apple"
XREADGROUP是一个写操作,只能在master节点上执行
读自己的pending消息:
> XREADGROUP GROUP mygroup Alice STREAMS mystream 0
确认消息:
> XACK mystream mygroup 1526569495631-0
(integer) 1
错误处理
假如一个consumer有pending的消息,然后crash了,然后再也不启动了,怎么办呢?Redis Stream提供了查询消息处理状态的命令XPENDING和转移消息所有者的命令XCLAIM
使用一个或者多个客户端,获取消息处于pending状态,指定group返回一个Summary:
> XPENDING mystream mygroup
1) (integer) 5
2) "1564401080073-0"
3) "1564401244891-0"
4) 1) 1) "Alice"
2) "1"
2) 1) "Bob"
2) "2"
3) 1) "Lily"
2) "2"
然后使用XPENDING命令获取每个Pending消息的信息
> XPENDING mystream mygroup 1564401080073-0 1564401244891-0 10
1) 1) "1564401080073-0"
2) "Alice"
3) (integer) 1818502
4) (integer) 4
2) 1) "1564401116987-0"
2) "Bob"
3) (integer) 590328
4) (integer) 1
3) 1) "1564401230270-0"
2) "Bob"
3) (integer) 590328
4) (integer) 1
4) 1) "1564401237686-0"
2) "Lily"
3) (integer) 416216
4) (integer) 1
5) 1) "1564401244891-0"
2) "Lily"
3) (integer) 416216
4) (integer) 1
使用范围和个数查询可以看到pending状态的消息在谁那里,停留了多少毫秒。对于停留时间过长的消息,可以使用XCLAIM将消息交给其他consumer处理。
> XCLAIM mystream mygroup Alice 50000 1564401116987-0
如果一个任务反复失败怎么办?
使用XPENDING命令可以查看一个任务被调度的次数,使用XREADGROUP和CLAIM都会增加一个任务被调度的次数。当这个次数达到一个设定的上限的时候,最好的处理方式是将这个任务放到另外一个Stream中,并通知任务失败。
这种任务也叫死信
Redis Stream中的消息和Group状态都会从主节点复制到从节点,并保持到AOF和RDB文件中。因此重启Redis会保存Stream中的状态。但是主节点崩溃仍可能有一些数据没有同步过去,如果应用程序对数据要求较高,可以使用WAIT命令等待数据主从同步完成。即使这样,在主库Crash的时候,还是有可能会丢失数据。
XINFO命令有很多子命令,比如查看Stream本身的状态使用XINFO STREAM
> XINFO STREAM mystream
1) length
2) (integer) 13
3) radix-tree-keys
4) (integer) 1
5) radix-tree-nodes
6) (integer) 2
7) groups
8) (integer) 2
9) first-entry
10) 1) 1524494395530-0
2) 1) "a"
2) "1"
3) "b"
4) "2"
11) last-entry
12) 1) 1526569544280-0
2) 1) "message"
2) "banana"
使用XINFO GROUPS查看组信息
> XINFO GROUPS mystream
1) 1) name
2) "mygroup"
3) consumers
4) (integer) 2
5) pending
6) (integer) 2
2) 1) name
2) "some-other-group"
3) consumers
4) (integer) 1
5) pending
6) (integer) 0
查看某一个Group中的Consumer:
> XINFO CONSUMERS mystream mygroup
1) 1) name
2) "Alice"
3) pending
4) (integer) 1
5) idle
6) (integer) 9104628
2) 1) name
2) "Bob"
3) pending
4) (integer) 1
5) idle
6) (integer) 83841983
Introduction to Redis Streams