Redis实现消息队列之发布订阅模式
Posted 架构技术栈
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis实现消息队列之发布订阅模式相关的知识,希望对你有一定的参考价值。
发布订阅(pub/sub)是一种消息通信模式:发送者(pub)在某一频道发送消息,订阅者(sub)接收消息。发布订阅模式类似与微博关注,比如说博主mango被张三、李四、王五关注,那么mango发一篇微博的时候张李王三人都会从关注里看到这条微博。
那么发布订阅和生产消费有何异同之处呢?生产消费主要是生成一个消息只能被一个客户端消费,而发布订阅可以理解为发布一条消息,在该频道中的所有客户端都会收到,所以有时候我们这个发布订阅类似广播。
注意pubsub是一个数据结构。
前面提到客户端能接受到消息首先要订阅频道,那么redis中的订阅命令subscribe channel [channel ...] 这里可以订阅多个频道。订阅后我们需要发布消息到这个频道中publish channel message。
####订阅test频道
> subscribe test
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "test"
3) (integer) 1
####发布信息
> publish test 'hello'
(integer) 1
不是可以广播嘛,那么我们再起一个客户端
当然redis还提供退订unsubscribe 跟subscribe 的使用方式一样。
PUBSUB是一个查看订阅与发布系统状态的内省命令,它由数个不同格式的子命令组成。
PUBSUB CHANNELS [pattern] 列出当前的活跃频道。活跃频道指的是那些至少有一个订阅者的频道, 订阅模式的客户端不计算在内。
pattern 参数是可选的:
如果不给出 pattern 参数,那么列出订阅与发布系统中的所有活跃频道。
如果给出 pattern 参数,那么只列出和给定模式 pattern 相匹配的那些活跃频道。
> pubsub channels
1) "test"
PUBSUB NUMSUB [channel-1 ... channel-N] 列出当前的活跃频道和返回连接数
> pubsub numsub test
1) "test" #频道
2) (integer) 2 #连接数
> pubsub numsub test1
1) "test1"
2) (integer) 0
PUBSUB NUMPAT 返回订阅模式的数量。
注意,这个命令返回的不是订阅模式的客户端的数量,而是客户端订阅的所有模式的数量总和,可以理解为模式匹配,例如订阅一个test*,客户端能接收test、test1、test2等等这样的,看下面例子。
####客户端
> psubscribe test*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "test*"
3) (integer) 1
> pubsub numpat
(integer) 1
模式匹配订阅
介绍完发布订阅的一般模式,此时我们小伙伴就问,长得跟mango一样的我能不能订阅呢?当然redis是支持这种模糊订阅的,其命令为psubscribe,跟subscribe使用方式一致。
> psubscribe test*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "test*"
3) (integer) 1
我们直到redis是key-value键值对的字典,PubSub前面讲过是一个数据结构,那么它是如何存储在内存中的呢?看老夫画图来解答。
我们从图中可以看到每个频道放入字典数组中,对应频道的订阅者则放入链表中,当我们发送一个publish命令时,首先字典数组遍历找到对应的频道,然后找到对应的订阅链,依次发送消息。
所以我们可以看出每次发送消息时我们的都需要遍历这个字典,也就是说它的执行时间效率为O(n),但是我们redis的宗旨是快,减少执行O(n)的命令,这违背了我们当初的初衷
PubSub的发布者传递过来一个消息,Redis会直接找到相应的订阅者传递过去。如果一个订阅者都没有,那么消息会被直接丢弃。如果开始有三个订阅者,第三个订阅者突然挂掉了,发布者会继续发送消息,另外两个订阅者可以持续收到消息,但是当挂掉的订阅者重新连上的时候,在断连期间发布者发送的消息,对于这个发布者来说就是彻底丢失了。
如果Redis停机重启,PubSub的消息是不会持久化的,毕竟Redis开机就相当于一个订阅者都没有,所有的消息会被直接丢弃。正是因为PubSub有这些缺点,在消息队列的领域它几乎找不到合适的应用场景。
所以Redis的作者单独开启了一个项目Disque专门用来做多播消息队列,不过该项目目前没有成熟,直处于Beta版本。
1.难以保证消息队列的ACK,消息发送出去后没有一个回馈过程,消息无法做持久化
2.如果保证消息持久化,那么必定损失性能,首先我们需要把消息存入磁盘,然后从磁盘中读取数据到内存去操作,这个过程是非常耗时的
3.PubSub执行效率低,执行效率是O(n),违背了redis设计初衷
4.难以实现复杂的消息模式
如果需要用到消息队列,还得需要使用专业的消息队列,毕竟这个技术已经相当成熟了
一名正在抢救的coder
笔名:mangolove
以上是关于Redis实现消息队列之发布订阅模式的主要内容,如果未能解决你的问题,请参考以下文章