Redis的发布与订阅命令由PUBLISH
,SUBSCRIBE
,PSUBSCRIBE
等命令组成。
通过执行SUBSCRIBE
命令, 客户端可以订阅一个或多个频道, 从而成为这些频道的订阅者: 每当有其他客户端向被订阅的频道发送消息时, 频道的所有订阅者都会收到这条消息。
除了订阅频道之外, 客户端还可以通过执行PSUBSCRIBE
命令订阅一个或多个模式, 从而成为这些模式的订阅者: 每当有其他客户端向某个频道发送消息时, 消息不仅会被发送给这个频道的所有订阅者, 它还会被发送给所有与这个频道相匹配的模式的订阅者.
频道的订阅与退订
当一个客户端执行SUBSCRIBE
命令订阅某个或某些频道的时候, 这个客户端与被订阅频道之间就建立起了一种订阅关系。
Redis将所有频道的订阅关系都保存在服务器状态的pubsub_channels
字典里面, 这个字典的键就是某个被订阅的频道, 而键的值则是一个链表, 链表里面记录了所有订阅这个频道的客户端:
struct redisServer { // 保存所有频道的订阅关系 dict *pubsub_channels; }
订阅频道
每当客户端执行SUBSCRIBE
命令订阅某个或某些频道的时候, 服务器会将客户端与被订阅的频道在pubsub_channels
字典中进行关联.
根据频道是否已经由其他订阅者, 关联操作分为两种情况执行:
-
如果频道已经有其他订阅者, 那么它在
pubsub_channels
字典中必然有相应的订阅者链表, 程序唯一要做的就是将客户端添加到订阅者链表的末尾. -
如果频道还未有任何订阅者, 那么必然不存在与
pubsub_channels
字典, 程序首先要在pubsub_channels
字典中为频道创建一个键, 并将这个键的值设置为空链表, 然后再将客户端添加到链表, 成为链表的第一个元素.
退订频道
UNSUBSCRIBE
命令的行为和SUBSCRIBE
命令的行为正好相反, 当一个客户端退订某个或某些频道的时候, 服务器将从pubsub_channels
中解除客户端与被退订频道之间的关联:
-
程序会根据被退订频道的名字, 在
pubsub_channels
字典中找到频道对应的订阅者链表, 然后从订阅者链表中删除退订客户端的信息 -
如果删除退订客户端之后, 频道的订阅者链表编程了空链表, 那么说明这个频道已经没有任何订阅者了, 程序将从
pubsub_channels
字典中删除频道对应的键.
模式的订阅与退订
服务将所有模式的订阅关系都保存在服务器状态的pubsub_patterns
属性里面:
struct redisServer { // 保存所有模式订阅关系 list *pubsub_patterns; }
pubsub_patterns
属性是一个链表, 链表中的每个节点都包含者一个pubsubPattern
结构, 这个结构的pattern属性记录了被订阅的模式, 而client属性则记录了订阅模式的客户端:
typedef struct pubsubPattern { // 订阅模式的客户端 redisClient *client; // 被订阅的模式 robj *pattern; }
订阅模式
每当客户端执行PSUBSCRIBE
命令订阅某个或某些模式的时候, 服务器会对每个被订阅的模式执行以下两个操作:
-
新建一个
pubsubPattern
结构, 将结构的pattern
属性设置为被订阅的模式,client
属性设置为订阅模式的客户端. -
将
pubsubPattern
结构添加到pubsub_patterns
链表的表尾。
退订模式
模式的退订命令PUNSUBSCRIBE
是PSUBSCRIBE
命令的反操作: 当一个客户端退订某个或某些模式的时候, 服务器将在pubsub_patterns
链表中查找并删除那些pattern
属性为被退订模式, 并且client
属性为执行退订命令的客户端的pubsubPattern
结构。
发送消息
当一个Redis客户端执行 PUBLISH <channel> <message>
命令将消息message发送给频道channel
的时候, 服务器需要执行以下两个动作:
-
将消息
message
发送给channel
频道的所有订阅者 -
如果有一个或多个模式pattern与频道channel相匹配, 那么将消息message发送给pattern模式的订阅者.
将消息发送给频道订阅者
因为服务器状态中的pubsub_channels
字典记录了所有频道的订阅关系, 所以为了将消息发送给channel
频道的所有订阅者, PUBLISH
命令要做的就是在pubsub_channels
字典里找到频道channel
的订阅者名单, 然后将消息发送给名单上的所有客户端。
将消息发送给模式订阅者
因为服务器状态中的pubsub_patterns
链表记录了所有模式的订阅关系, 所以为了将消息发送给所有与channel频道相匹配的模式的订阅者, PUBLISH
命令要做的就是遍历整个pubsub_patterns
链表, 查找那些于channel频道相匹配的模式, 并将消息发送给订阅了这些模式的客户端.
将消息发送给模式订阅者
因为服务器状态中的pubsub_patterns
链表记录了所有模式的订阅关系, 所以为了将消息发送给所有与channel频道相匹配的模式的订阅者, PUBLISH
命令要做的就是遍历整个pubsub_patterns
链表, 查找那些鱼channel频道相匹配的模式, 并将消息发送给订阅了这些模式的客户端。
查看订阅信息
PUBSUB
命令是Redis 2.8
新增加的命令之一, 客户端可以通过这个命令来查看频道或者模式的相关信息。
PUBSUB CHANNELS
PUBSUB CHANNELS [patterns]
子命令用于返回服务器当前被订阅的频道, 其中pattern
参数是可选的:
-
如果不给定
pattern
参数, 那么命令返回服务器当前被订阅的所有频道 -
如果给定
pattern
参数, 那么命令返回服务器当前被订阅的频道中那些与pattern
模式相匹配的频道.
PUBSUB NUMSUB
PUBSUB NUMSUB [channel-1, channel-2...channel-n]
自命令接收多个频道作为输入参数, 并返回这些频道的订阅者数量. 该命令返回的是pubsub_channels
中对应的channel下的链表元素数量.
PUBSUB NUMPAT
PUBSUB NUMPAT
自命令用于返回服务器当前被订阅模式的数量。
这个自命令是通过返回pubsub_patterns