• 频道的订阅与退订
  • 订阅频道
  • 退订频道
  • 模式的订阅与退订
  • 订阅模式
  • 退订模式
  • 发送消息
  • 将消息发送给频道订阅者
  • 将消息发送给模式订阅者
  • 查看订阅信息
  • Pubsub Channels
  • Pubsub NumSub
  • Pubsub NumPat
  • 总结


Redis的发布与订阅功能由Publish、Subscribe、Psubscribe等命令组成

redis数据中backup3是什么 redis psubscribe_客户端

频道的订阅与退订

订阅使用的命令是Subscribe或者Psubscribe

Subscribe是指定订阅频道的名字,而Psubscribe是指定订阅频道的模式(名字的模式)

当一个客户端执行Subscribe命令去订阅某个或某些频道的时候,这个客户端与被订阅的频道之间就建立起了一种订阅关系

Redis将所有频道的订阅关系都保存在服务器状态里面的pubsub_channels字典里面(使用的是字典结构),字典的键是某个被订阅的频道,而键的值则是一个链表,链表里面保存的是所有订阅了该频道的客户端

struct redisServer(
	//...
    //保存所有客户端与频道的订阅关系
    dict *pubsub_channel;
    //...
);

redis数据中backup3是什么 redis psubscribe_服务器_02

订阅频道

每当客户端执行Subscribe命令去订阅某个或某些频道的时候,服务器都会将客户端与被关联的频道在pubsub_channels字典中进行关联。

并且根据该频道是否有其他订阅者,再细分情况去执行

  • 如果频道中已经有其他订阅者,那么它在pubsub_channels字典中必然有相应的 订阅者链表,Redis服务器唯一要做的就是将客户端添加到订阅者链表的末尾
  • 如果链表还未有任何的订阅者,也就是该频道无人订阅,那么它必然不存在于pubsub_channels字典,程序首先会在pubsub_channels字典中为频道创建一个键,然后键对应的值就设置为一个空链表,然后再将此时订阅的客户端添加到链表,称为链表的第一个元素

退订频道

Unsubscribe命令的行为和Subscribe命令的行为正好相反,当一个客户端退订某个频道时候,服务器会将从pubsub_channels中解除客户端与被退订频道之间的关联,也是分情况去进行

  • 程序会根据被退订频道的名字,在pubsub_channels字典中会找到频道对应的订阅者链表,然后从订阅者链表中删除客户端的信息
  • 如果删除退订客户端之后,频道的订阅者链表变成了空链表,那么说明这个频道已经没有客户端去订阅了,那么程序将会从pubsub_channels字典中删除频道对应的键

用伪代码去表示

def unsubscribe(*all_input_channels) //参数为退订的频道
	#首先遍历要退订的所有频道
	for channel in all_input_channels:
		#在该频道的订阅者链表中删除退订的客户端
		server.pubsub_channels[channel].remove(client);
		#判断该频道是否还有订阅者
		#订阅者的链表为空,代表没有任何订阅者了,那么将频道从字典中删除
		if(len(server.pubsub_channels[channels]) == 0);
			server.pubsub_channels.remove(channel)
	end for
end unsubscribe

模式的订阅与退订

订阅与退订除了可以指定频道名字去进行,其实还可以指定频道模式去进行(模式是指频道名字模式)

不过按指定频道模式去保存就不在是前面提到的pubsub_channels字典(pubsub_channels),而是会使用服务器状态的另一个属性,名为(pubsub_patterns)的链表

struct redisServer(
	//...
    //保存所有模式订阅关系
    list *pubsub_patterns;
    //...
);

pubsub_patterns属性是一个链表,而链表中的每个节点都包含着一个pubsub pattern,这个结构的pattern属性记录了频道被订阅的模式,而client属性则记录了订阅模式的客户端

typedef struct pubsubPattern(
	//订阅模式的客户端
    redisClient *client;
    //被订阅的模式
    robj *pattern;
);

redis数据中backup3是什么 redis psubscribe_redis_03

订阅模式

每当客户端执行Psubscribe命令订阅某个或某些类型的时候,服务器会对每个被订阅的模式执行以下操作

  • 新建一个pubsubPattern结构,将结构的pattern属性设置为被订阅的模式,client属性设置为订阅模式的客户端状态
  • 将pubsubPattern结构添加到pubsub_patterns链表的表尾(使用尾插法)

所以可以用下面伪代码来表示

def psubscribe(*all_input_patterns)
    #遍历输入的所有模式
    for pattern in all_input_patterns:
		#创建新的pubsubPattern结构
		pubsubPattern = create_new_pubsubPattern();

		#记录被订阅的模式,以及订阅模式的客户端
		pubsubPattern.client = client;
		pubsubPattern.pattern = pattern;

		#将新的pubsubPattern追加到pubsub_patterns链表末尾
		server.pubsub_patterns.append(pubsubPattern);
	end For
end Psubscribe;

退订模式

模式的退订命令Punsubscribe是Psubscribe命令的反操作

当一个客户端Punsubscribe退订某个或某些模式的时候,程序是先要在pubsub_patterns链表中查找并删除那些pattern属性为被退订模式,并且client属性为执行退订命令的客户端的pubsubPattern结构

def punsubscribe(*all_input_patterns)
    #遍历所有要退订的模式
    for pattern in all_input_patterns:
		#遍历pubsub_patterns链表中的所有pubsubPattern结构
		for patterns in server.pubsub_patterns:
			#如果当前客户端和patterns记录的客户端相同
			#并且当前要退订的模式与patterns记录的模式相同
			if(client == patterns.client and
              pattern == patterns.pattern)
                #那么就进行移除
                server.pubsub_patterns.remove(patterns)
       End for
    End for
end punsubscribe;

发送消息

发送消息使用的命令为Publish,可以指定频道,也可以指定模式

当使用该命令时,服务器需要执行两个动作(也就是既要去pubsub_channels里找,也要去pubsub_patterns去找

  1. 将消息message发送给channel频道的所有订阅者
  2. 如果有一个或多个模式Pattern与频道Channel相匹配,那么将消息Message发送给Pattern模式的订阅者

将消息发送给频道订阅者

服务器状态中的pubsub_channels字典记录了所有频道的订阅关系,所以首先要做的是,在pubsub_channels字典里找到频道channel的订阅者名单(字典里面的值储存了订阅者名单链表),然后将消息发送给名单上的所有客户端,指定频道只有一个订阅者链表

将消息发送给模式订阅者

服务器状态中的pubsub_patterns链表记录了所有模式与客户端的订阅关系,所以首先要做的是,遍历链表所有与channel频道相匹配的模式的订阅者,通过匹配链表里面的每一个pubsubPattern结构里面的pattern,找到一个就发送一个,不会再另外存储起来再统一发送

查看订阅信息

Pubsub Channels

PUBSUB命令是用来查看当前客户端订阅信息的,可以用来查看频道或者订阅模式的相关信息

pubsub channels [pattern]

其中pattern参数是可选的

  • 如果不给定pattern参数,那么命令返回服务器当前被订阅的所有频道
  • 如果给定pattern参数,那么命令返回服务器当前被订阅的频道中与Pattern模式相匹配的频道

注意这里的是订阅的所有频道,不包括模式

这个命令是通过遍历服务器pubsub_channels字典的所有键来实现的

Pubsub NumSub

Pubsub NumSub[channel1] [chennel2] ...

这个命令可以接收任意多个频道作为输入参数,并返回这些频道的订阅者数量。

该命令的实现就是通过在pubsub_channels字典中找到频道对应的订阅者链表,然后返回订阅者链表的长度来实现的

Pubsub NumPat

pubsub numpat

该命令用于返回服务器当前被订阅模式的数量

通过返回pubsub_patterns链表的长度来实现的,因为该链表长度就是被订阅模式的数量。

总结

  • 服务器状态使用pubsub_channels字典保存所有频道的订阅关系,SubScribe命令负责将客户端和被订阅的频道关联到这个字典里面
  • 服务器状态使用pubsub_patterns链表保存所有频道模式的订阅关系,Psubscribe命令负责将客户端和被订阅的频道模式关联到这个链表里面
  • Publish命令,不仅要在Pubsub_channnel中找到对应的客户端还要在pubsub_patterns里找到对应的客户端
  • 查看订阅信息的三个命令都是使用服务器状态的Pubsub_channels字典和pubsub_patterns链表实现的