Redis Stream(2)
消费组
Redis流的消费组允许用户将一个流从逻辑上划分为多个不同的流,并让消费组组属下的消费者去处理组中的消息。
创建消费者组
# 通过XGROUP CREATE 命令创建消费者组
XGROUP CREATE stream group start_id
- stream:指定流的名字
- group:指定将要创建的消费者组的名字
- start_id:用于指定消费者组在流中的起始ID,这个ID决定消费者组从流的哪个ID之后进行读取。
同一个流的消息在不同消费者组之间是共享的而不是独占的。流中的同一条消息可以被多个不同组的消费者读取,并且来自不同消费者组的读取操作不会对其它消费者组的读取操作产生任何影响。
读取消费者组
XREADGROUP GROUP group consumer [COUNT N] [BLOCK ms] STREAMS stream [stream ...] id [id ...]
这个命令基本参数及作用与XREAD命令大同小异,主要区别在于新增的GROUP group consumer ,分别用于指定被读取的消费者组以及负责处理消息的消费者。
消费者组在创建之后就会跟踪并维护一系列信息和数据结构,其中包括:
- 该组属下的消费者名单。
- 一个队列,记录了该组目前处理“待处理”状态的所有消息。
- 该组最后递送的消息的ID。
当用户调用XREADGROUP命令对消费者组进行读取之后,命令就会按需更新上述三项信息。
XREADGROUP GROUP g1 c1 STREAMS msgs 0
假设读取一条ID为10086的信息,那么命令对消费者组的相关信息执行以下更新。
- 如果消费者c1是第一次读取这个消费者组,那么将该消费者添加到该组的消费者名单中。
- 将被读取的消息添加到该组的待处理消息队列中。
- 将10086设置为该组的最后提送的消息ID。
对于创建之后还未执行任何读取操作的新消费者组来说,该组的最后递送消息ID就是用户创建消费者组时给定的起始ID。
消费者
消费者就是负责处理消息的客户端。消费者不用显式创建,用户只要在执行XREADGROUP命令时给定消费者的名字,Redis就会自动为新出现的消费者创建相应的数据结构。
消费者也会维护一个属于自己的待处理消息队列:每当使用XREADGROUP命令读取出一条消息,并将这条消息指派给一个消费者处理时,该消费者就会把所指派的消息添加到自己的待处理消息队列中。
同一消费者组中的每条消息只能有一个消费者。
消息状态转换
当消费者处理完一条消息之后,他需要向REDIS发送一条针对该消息的XACK命令
XACK stream group id [id id ...]
当Redis接受到消费者发来的XACK命令之后,就会在消费者的待处理队列中移除指定消息。消息的状态就会从”待处理“转换为”已确认“,表示消费者已经处理完这些消息。
XGROUP 管理消费者组
创建消费者组
XGROUP CREATE stream group id
复杂度:O(1)
修改消费者组的最后递送消息ID
XGROUP SETID stream group id
ID可以是任意合法的消息ID,ID对应的消息不必实际存在,并且新ID可以大于、小于等于当前ID。id可以为“$”,表示把消费者组的最后递送消息ID设置为流的最新消息的ID。
#使用XINFO查看当前消费组的信息
XINFO GROUPS cgs #cgs为stream的key
# 修改最后递送的消息ID
XGROUP SETID cgs all-message 0
XGROUP SETID显式修改最后递送消息ID对后续执行XREADGROUP命令的结果产生影响如下:
- 如果新ID大于旧ID,那么消费者可能会漏掉一些原本应该读取的消息。
- 如果新ID小于旧ID,那么消费者可能重新读取到一些之前已经被确认的消息。
时间复杂度:O(1)
删除消费者
XGROUP DELCONSUMER stream group consumer
# 返回一个数字作为结果,数字是消费者被删除时,他仍在处理的消息数量
消费者被删除之后,他在被删除时处理的消息也会从消费者的待处理消息队列中移除。可能这些消息未得到妥善处理,因此在删除一个消费者之前应该确保递送给他的消息均已处理完成。或者使用XCLAIM命令显式转移待处理消息的归属权。
删除消费者组
XGROUP DESTORY stream group
# 命令成功执行返回1,否则返回0
为了保证程序的正确性,用户需要保证在删除消费者组的时候,组中已经没有任何待处理消息,否则这些待处理消息可能无法得到妥善处理。
复杂度:O(N+M),N为待处理状态的消息数量,M该组属下的消费者数量,
XREADGROUP 读取消费组中的消息
XREADGROUP GROUP group consumer [COUNT n] [BLOCK ms] STREAMS stream [stream] id [id..]
XREADGROUP GROUP all-message work1 count 1 streams cgs 10086
STREAMS选项指定的ID可以是以下两种之一:
- 特殊ID>,意味着消费者希望只接受从未发送到任何其它消费者的消息,这意思是说,请给我新消息。
- 任意其它的ID,即0或任意其它有效ID。将具有返回发送命令的消费者的待处理条目的效果。只能访问它的待处理条目(已发送,但未确认的条目)。
读取消息的同时,还会将该消息分别添加到消费者组的待处理消息队列以及消费者待处理消息队列中,从而使得读取消息状态从未传递到待处理。消费者组的待处理消息队列记录所有已经被递送但是尚未被确认的待处理消息。
可以使用下述命令进行验证
# 查看消费者组all-message的待处理消息队列
XPENDING cgs all-message
# 查看消费者work1的待处理消息队列
XPENDING cgs all-message - 1 work1
读取未递送过的新消息
XREADGROUP 命令在不知道最后一条消息ID的情况下,获取新出现的消息只需要将id设置为特殊符号>,命令就会自动的向消费者返回尚未递送过的新消息。
XREADGROUP GROUP all-message work1 streams cgs >
XPENDING 显示待处理消息的相关信息
获取指定流的指定消费者组目前待处理消息的相关信息。命令格式
XPENDING stream group [start stop count] [consumer]
- start 、stop:限定消息的ID范围区间。
- count 限制被检阅的消息数量
- consumer:只列出与给定消费者相关联的待处理消息。
返回信息包括待处理消息的数量、待处理消息队列中首条消息和最后一条消息的ID,以及该组名下各个消费者正在处理的消息数量。
获取待处理消息更详细的信息
xpending cgs all-message 1679316694435-0 1679316694435-0 1
1) 1) "1679316694435-0" # 消息ID
2) "work" # 所属消费者
3) (integer) 2291 # 消息最后以此投递给消费者,过去多少毫秒
4) (integer) 2 # 消息被递送的次数
XACK 将消息标记为"已处理"
通过执行XACK命令,用户可以将消费者组中指定的消息标记为已处理,被标记的消息从当前消费者待处理消息队列中移除,之后的XREADGROUP命令不会再读取这些消息
XACK stream group id [id id ...]
#使用
xack cgs all-message 1679316694435-0
# 可以使用xpending查看影响
xpending cgs all-message - + 1 work
XCLAIM转移消息的归属权
将指定消息的归属权从一个消费者转向另一个消费者。
XCLAIM stream group new_consumer max_pending_time id [id id ..]
- stream:指明所在流
- group:指明消费组
- new_consumer:执行消息的新消费者
- id 指明了需要转移归属权的消息
- max_pending_time: 指定了执行归属权转移操作所需的最大消息处理实现
- 如果XCLAIM命令执行时,消息原来的消费者用在处理该消息上的时间已经超过指定的时限,那么归属权转移操作就会被执行。
- 与此相反,如果原消费者处理该消息的时间并未超过给定的时限,或者该消息已经被原消费者确认,那么归属权转移操作就会被放弃执行。
XINFO查看流和消费者组的相关信息
打印消费者信息
# 打印指定消费者组的所有消费者
XINFO CONSUMERS stream group-name
打印消息包含:消费者名字、正在处理的消息数量以及消费者的闲置时长。
打印消费组信息
# 打印与指定流相关联的消费组,以及这些消费者组的相关信息
XINFO GROUPS stream
打印流信息
XINFO STREAM stream
打印信息包含:
- 流的长度(包含的消息数量)
- 流在底层基础树表示的相关信息
- 流相关的消费组数量
- 流最后生成的消息ID以及流的第一个节点以及最后一个节点。