一、概述
Redis提供了基于“发布/订阅”模式的消息机制,当一个客户端通过 PUBLISH 命令向订阅者发送信息的时候,我们称这个客户端为发布者(publisher)。而当一个客户端使用 SUBSCRIBE 或者 PSUBSCRIBE命令接收信息的时候,我们称这个客户端为订阅者(subscriber)。
为了解耦发布者(publisher)和订阅者(subscriber)之间的关系,Redis 使用了 channel (频道)作为两者的中介 —— 发布者将信息直接发布给 channel ,而 channel 负责将信息发送给适当的订阅者,发布者和订阅者之间没有相互关系,也不知道对方的存在。
二、命令
1. 发布消息
publish channel message
2. 订阅消息
subscribe channel [channel …]
客户端在执行订阅命令之后进入了订阅状态,只能接收subscribe、psubscribe、unsubscribe、punsubscribe的四个命令。
新开启的订阅客户端,无法收到该频道之前的消息,因为Redis不会对发布的消息进行持久化。
3. 取消订阅
unsubscribe [channel [channel …]]
4. 按照模式订阅和取消订阅
psubscribe pattern [pattern…]
punsubscribe [pattern [pattern …]]
5. 查询订阅
查看活跃的频道,pubsub channels [pattern]
查看频道订阅数,pubsub numsub [channel …]
查看模式订阅数,pubsub numpat
三、订阅的实现
Redis将所有的订阅关系都保存在服务器的名为pubsub_channels的字典表内,字典表的键为频道名,值为链表,表中保存客户端信息。
普通订阅:
模式订阅
与与普通订阅原理一致,字典表为pubsub_patterns
订阅步骤:
- 频道没有订阅者,则先在字典中为新的频道创建一个键,并将这个键的值设置为空链表,然后在将客户端添加到链表中,成为链表的第一个元素。
- 频道已经有订阅者,那么它在pubsub_channels字典中必然有相应的订阅者链表,只要将客户端加到订阅者链表的末尾。
四、退订实现
client-10086退订 “news.sport”,“news.movie”
原字典表数据:
退订完成字典数据:
- 程序会根据被退订频道的名字, 在 pubsub_channels 字典中找到频道对应的订阅者链表,
然后从订阅者链表中删除退订客户端的信息。 - 如果删除退订客户端之后, 频道的订阅者链表变成了空链表, 那么说明这个频道已经没有任何订阅者了, 程序将从 pubsub_channels字典中删除频道对应的键。
五、发布实现
在 pubsub_channels字典里找到对应的频道,依次遍历将效发送给所有的订阅者。
六、Redis发布订阅与ActiveMQ的比较
(1)ActiveMQ支持多种消息协议,包括AMQP,MQTT,Stomp等,并且支持JMS规范,但Redis没有提供对这些协议的支持;
(2)ActiveMQ提供持久化功能,但Redis无法对消息持久化存储,一旦消息被发送,如果没有订阅者接收,那么消息就会丢失,如果订阅者故障重新连接,重新连接这个过程中新发布的消息无法订阅,消息丢失;
(3)ActiveMQ提供了消息传输保障,当客户端连接超时或事务回滚等情况发生时,消息会被重新发送给客户端,Redis没有提供消息传输保障。
总之,ActiveMQ所提供的功能远比Redis发布订阅要复杂,毕竟Redis不是专门做发布订阅的,但是如果系统中已经有了Redis,并且需要基本的发布订阅功能,就没有必要再安装ActiveMQ了,因为可能ActiveMQ提供的功能大部分都用不到,而Redis的发布订阅机制就能满足需求。