Redis的发布订阅功能有以下命令组成:
-
SUBSCRIBE channel [channel ...]
-
订阅给定的一个或多个频道的信息;
-
SUBSCRIBE channel
-
-
UNSUBSCRIBE [channel [channel ...]]
-
退订给定的频道
-
UNSUBSCRIBE channel
-
-
PUBLISH channel message
-
用于将信息发送到指定的频道;
-
PUBLISH channel itzhai.com
-
-
PUBSUB subcommand [argument [argument ...\]]
-
查看订阅与发布系统状态
-
PUBSUB CHANNELS
-
-
PSUBSCRIBE pattern [pattern ...]
-
订阅一个或多个符合给定模式的频道
-
PSUBSCRIBE site.*
-
-
PUNSUBSCRIBE [pattern [pattern ...\]]
-
退订给定模式的频道
-
UNSUBSCRIBE site.*
-
如下,通过给定的模式频道进行订阅和发布消息:
1 | # 客户端A订阅模式频道 |
Redis在服务端通过链表的形式维护了每个频道的客户端的订阅记录,每次发布消息的时候,都从链表中找到所有相关的客户端的socket连接,并发送订阅消息给各个客户端。Redis中存放客户端订阅关系的相关数据结构:
1 | struct redisServer { |
具体结构如下图所示:
在dict字典中,每个键值对存储一个频道的订阅关系,key为频道名称,value为链表结构,存储该频道所有订阅的客户端。
每当执行SUBSCRIBE命令的时候,执行把客户端追加到字典中对应频道的key的values链表中即可。
每当执行PUBLISH命令的时候,从字典中找到对应的频道键值对,依次遍历values中所有的客户端进行发送消息即可。
在list链表中,保存了所有的模式频道订阅关系。
每当执行PUBLISH命令的时候,除了在pubsub_channels寻找频道订阅关系,发给具体的频道的所有客户端之外,同时,Redis会遍历pubsub_patterns中的所有订阅模式频道,找到与当前发布消息频道匹配的模式频道,将消息发送给该模式频道的客户端。
1、发布订阅的优缺点
通过使用Redis的发布订阅机制,很容易实现消息的订阅与通知,可以快速实现一个消息队列。
但是,该消息队列的缺点也比较明显,请大家慎用:
- 发布的消息不支持持久化,如果Redis挂了,那么发布的消息也就丢失了;或者消息发送给了一半的订阅者,Redis就挂了,那么剩下的一般订阅者也就不会收到消息了;或者准备发送消息给其中一个订阅者的时候,该订阅者失去连接了,消息也会丢失;
- 消息发送缺少ACK机制,不能保证消息一定会被消费…
针对可靠性要求低的业务,为了简单快速实现,可以使用Redis的发布订阅机制来实现消息通知。而对于可靠性要求比较高的,则可以尝试Redis 5.0的新数据结构Stream,具体用法和原理,参考Part I部分相关内容。