Redis也可以使用list类型实现消息队列,但是不支持消息的多播机制。
为了支持消息多播,Redis单独使用了一个模块来支持消息多播,也就是本章要讲的PubSub。
Redis作为消息发布和订阅之间的服务器,起到桥梁的作用,在Redis里面有一个channel的概念,也就是频道,发布者通过指定发布到某个频道,只要有订阅者订阅了该频道,该消息就会发送给订阅者。
Redis的发布与订阅的功能应用还是比较广泛的,它的应用场景有很多。比如:最常见的就是实现实时聊天的功能,还是有就是博客的粉丝文章的推送,当博主推送原创文章的时候,就会将文章实时推送给博主的粉丝。
演示
首先启动消费者,然后在执行生产者。消费者可以启动多个,PubSub会保证它们收到的都是相同的消息序列。
消费者
打开一个窗口,这个窗口用来订阅频道。
订阅命令格式:SUBSCRIBE channel [channel …]
,使用subscribe test就表示订阅来test这个频道。订阅后返回了三条信息。
示例:
redis> subscribe test
Reading messages... (press Ctrl-C to quit)
1) "subscribe" # 返回值的类型:显示订阅成功
2) "test" # 订阅的频道名字
3) (integer) 1 # 目前已订阅的频道数量
1) "message" # 返回值的类型:信息
2) "test" # 来源(从那个频道发送过来)
3) "hello" # 信息内容
生产者
再打开一个新窗口,用来发布消息,命令格式:PUBLISH channel message
。
示例:
redis> publish test 'hello'
(integer) 1 # 接收到信息的订阅者数量
取消订阅
若是想取消之前的订阅可以使用unsubscribe命令,格式为:UNSUBSCRIBE [channel [channel …]]
。
如果没有频道被指定,也即是,一个无参数的 UNSUBSCRIBE 调用被执行,那么客户端使用 SUBSCRIBE 命令订阅的所有频道都会被退订。在这种情况下,命令会返回一个信息,告知客户端所有被退订的频道。
示例:
redis> unsubscribe test
1) "unsubscribe" # 返回值的类型
2) "test" # 频道的名称
3) (integer) 0 # 该频道订阅的数量
按模式订阅
上面演示的订阅模式是基于名称订阅的,消费者订阅的是指定名称的频道,如果想增加一个频道,客户端也必须跟着增加一个订阅指令才能收到新频道的消息推送。为了简化订阅的繁琐,可以使用PSUBSCRIBE pattern [pattern …]
订阅一个或多个符合给定模式的频道。
每个模式以 * 作为匹配符,比如 it* 匹配所有以 it 开头的频道( it.news 、 it.blog 、 it.tweets 等等), news.* 匹配所有以 news. 开头的频道( news.it 、 news.global 等等)。
示例:
redis> psubscribe t*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe" # 返回值的类型:显示订阅成功
2) "t*" # 订阅的模式
3) (integer) 1 # 目前已订阅的模式的数量
1) "pmessage" # 返回值的类型:信息
2) "t.*" # 信息匹配的模式
3) "test" # 信息本身的目标频道
4) "heoll 2" # 信息的内容
取消按模式订阅
如果想取消之前的按模式订阅,可以使用PUNSUBSCRIBE [pattern [pattern …]]
来取消。
示例:
redis> PUNSUBSCRIBE t*
1) "punsubscribe"
2) "t*"
3) (integer) 0
查看订阅消息
PUBSUB 是一个查看订阅与发布系统状态的命令,格式:bashPUBSUB CHANNELS [pattern]
。
pattern 参数是可选的:
- 如果不给出 pattern 参数,那么列出订阅与发布系统中的所有活跃频道。
- 如果给出 pattern 参数,那么只列出和给定模式 pattern 相匹配的那些活跃频道。
返回值
一个由活跃频道组成的列表。
PubSub缺点
PubSub的生产者传递过来一个消息,Redis会找到对应的消费者传递过去。如果一个消费者都没有,那么消息直接丢弃。
如果有多个消费者,一个消费者突然断开连接,生产者会继续发送消息,其他正常连接的消费者可以持续收到消息。断开的消费者重新连接上,在断联期间生产者发送的消息,对这个消费者来说是彻底丢失了。
如果Redis停机重启,PubSub的消息是不会持久化的,所有的消息都会被直接丢弃。因为这些缺点,消息队列领域几乎找不到合适的应用场景。
补充:
Redis5.0新增了Stream数据结构,这个功能给Redis带来了持久化消息队列,从此PubSub作为消息队列的功能可以消失了。