PubSub & Stream
PubSub
简单队列
在Pub成功后进行Sub有时得不到消息,需要延迟以下
在没有消息时Sub直接返回空而不会阻塞,也有阻塞的方法
要先启动Sub,否则启动前的Pub发的信息收不到,另外如果Sub挂了Redis是不会补推的
Redis重启时所有消息都会丢失,毕竟这时Redis认为所有Sub都没了
模式订阅
这个和RabbitMQ的TopicExchange类似,通过*来做匹配
Stream
Stream相对于PubSub的两点,一个是重启不会丢失数据,另外一个是有了Consumer Group(通过xgroup create显式创建,创建时需指定从哪个消息开始消费)
消费者内部会有一个状态变量pending_ids,它记录了当前已经被客户端读取,但是还没有ack的消息.如果客户端没有ack,这个变量里面的消息ID就会越来越多,一旦某个消息被ack,它就开始减少.这个pending_ids变量在Redis官方被称为PEL,也就是Pending Entries List,这是一个核心的数据结构,它用来确保客户端至少消费了消息一次,而不会在网络传输的中途丢失了而没被处理.
id
消息ID的形式是timestampInMillis-sequence
id也可以通过xadd手工指定,但是必须比前面的id大,否则报错,这也意味着如果使用了手工,就不能再自动了.按照官方说明,这个一般用来一些小众场景,例如要和DB的id保持一致
队列指令
xadd
向Stream追加消息,语法如下,其中*表示id自动产生
XADD mystream * field1 value1 field2 value2 field3 value3
maxlen
可以通过这个参数控制消息队列长度,示例如下
xadd codehole maxlen 3 * name xiaorui age 1
上面指令执行后,长度不会超过3
xdel
按照官网说法给消息设置标志位,不影响消息总长度.真正的删除发生在整个macro-node里所有entry都被标记
官网给出的这一指令的用处:
This may be useful, for instance, in order to comply with certain privacy policies.
xrange
这里使用的是closed interval,不会包括删除消息(这不是显然么),使用下面语法返回所有
XRANGE somestream - +
另外如果参数有自动补全功能,官方说明如下
XRANGE will auto-complete the start interval with -0 and end interval with -18446744073709551615, in order to return all the entries that were generated between a given millisecond and the end of the other specified millisecond.
count
可以通过count来指定数量,官网例子如下:
XRANGE somestream 1526985054069-0 + COUNT 1
1) 1) 1526985054069-0
2) 1) "duration"
2) "72"
3) "event-id"
4) "9"
5) "user-id"
6) "839248"
xlen
这里有一个坑,就是如果队列不存在会返回0,所以还需要进一步使用type或者exists来明确是空队列还是不存在,另外根据我的测试,当xdel后长度会减少
消费指令
无组
xread
这个命令把Stream当做一个list看待,从一个指定的地方向后读取
完整语法如下
XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key …] id [id …]
count
指出需要消费多少消息
block
阻塞多少毫秒,0表示一直阻塞
xgroup
完整语法如下
XGROUP [CREATE key groupname id-or- ] [ S E T I D k e y g r o u p n a m e i d − o r − ] [SETID key groupname id-or- ][SETIDkeygroupnameid−or−] [DESTROY key groupname] [DELCONSUMER key groupname consumername]
create
一般用0-0表示从头消费,而**$**表示结尾
xreadgroup
和xread类似,只是有了读组内消息
xinfo
可以使用xinfo groups key来查看group消息,也可以通过xinfo consumers key consumer来读取消费者信息,其中consumer来自于前一个指令
高可用
不过鉴于Redis的指令复制是异步的,在failover发生时,Redis可能会丢失极小部分数据,这一点Redis的的其他数据结构也是一样的