天天看点

Redis之PubSub消息多播PubSub订阅模式消息结构缺点

消息多播

使用Redis的 list 和 zset 数据结构分别可以实现队列与延时队列的功能,但是这两种实现没有办法做到多播,即一份消息可以让多个消费者消费,

消息多播是生产只需要生产一份消息,中间件负责将消息复制到多个消息队列中,每个消息队列由对应的消费组进行消费,

消息多播是分布式系统常用的一种解耦方式,每个消费组的处理逻辑不同,可以将消费组放在不同的系统中,

Redis之PubSub消息多播PubSub订阅模式消息结构缺点

如果消息只有一份的话,则只能将所有的处理逻辑放在同一个系统中,不同的消费组通过内部传递共同使用一份消息。

Redis之PubSub消息多播PubSub订阅模式消息结构缺点

PubSub

Redis通过 PubSub 模块支持消息多播,即 PublisherSubscriber (发布/订阅者模式)。

Java使用Jedis演示消息多播:

Redis之PubSub消息多播PubSub订阅模式消息结构缺点

可以看到一个发布者发布的消息可以被多个消费者消费到,

需要注意的是生产者和消费者的连接必须使用不同的连接,redis不允许连接在subscribe消息时进行其他操作。

完整代码:

https://github.com/qiaomengnan16/redis-demo/tree/main/redis-pub-sub

订阅模式

多主题

消息订阅支持消费者订阅多个主题,即 subscribe 多个主题名称

127.0.0.1:6379> subscribe c1 c2 c3

Reading messages... (press Ctrl-C to quit)

1) "subscribe"

2) "c1"

3) (integer) 1

1) "subscribe"

2) "c2"

3) (integer) 2

1) "subscribe"

2) "c3"

3) (integer) 3           

publish给多个主题发送消息

127.0.0.1:6379> publish c1 helloc1

(integer) 1

127.0.0.1:6379> publish c2 helloc2

(integer) 1

127.0.0.1:6379> publish c3 helloc3

(integer) 1

127.0.0.1:6379>           

此时可以看到,消费者收到了多个主题的消息。

Redis之PubSub消息多播PubSub订阅模式消息结构缺点

模式订阅

如果此时需要新增c4、c5主题的话,客户端又需要重新进行 subscribe 将需要订阅的加入进去,

因此redis提供了 pattern subscribe,这样就可以一次订阅多个主题,即使增加了新主题,消费者也可以立即收到消息。

即 psubscribe c* ,订阅c开头的主题,这样所有c开头的消息,这边都能消费到了。

Redis之PubSub消息多播PubSub订阅模式消息结构缺点
127.0.0.1:6379> psubscribe c*

Reading messages... (press Ctrl-C to quit)

1) "psubscribe"

2) "c*"

3) (integer) 1

1) "pmessage"

2) "c*"

3) "c4"

4) "helloc4"

1) "pmessage"

2) "c*"

3) "c5"

4) "helloc5"
           

消息结构

消费者接收到消息时不单单仅有message一个信息,还有其他几个内容。

  1. data 即消息的内容。
  2. channel 即订阅主题名称。
  3. type 消息类型,取值有 message(普通消息)、subscribe(订阅指令反馈)、psubscribe(模式订阅反馈)、unsubscribe(取消订阅指令反馈)、punsubscribe(取消模式订阅反馈)。
  4. pattern 即当前消息使用哪种模式订阅得到,通过 subscribe 订阅的即为空。

缺点

当生产者发布一个消息时,Redis会找到相应的消费者发送过去,如果没有消费者的话,此时这个消息将被丢弃,

如果有三个消费者,挂掉了一个,另外两个可以正常消费生产者的消息,但是挂掉的那个消费者重连的时候,挂掉期间内的消费,将无法消费到,即丢消息了,

PubSub的消息不会被持久化,因此Redis重启或者宕机,这些消息将会被直接丢弃。

由于PubSub无法保证消息的可靠性,易丢失,在需要保证消息可靠性的消息队列的场景中,基本没有合适的应用场景,

如果需要保证消息的可靠性,Redis5.0新增了Stream数据结构,该结构支持持久化,但是PubSub不是一无是处,适用于一些时效性要求高的场景。

例如Master要求所有的Slave上报一下当前自身的负载,可以用过PubSub发布一条指令,如果有Slave处于宕机状态也没事,

宕机自然无法上传,宕机恢复后也不需要再上传,因为过了时效性,只需后面收到指令时在汇报实时的负载即可,

如果作为指令中介的Redis实例重启或宕机,消息也没必要持久化指令在队列中,因为当Redis恢复后已经过了要求上报的时效期,

也可以用作在线集群间的通信,例如一个节点通知其他节点,给所有在线节点发送一个消息。