详解Redis —— 发布与订阅(上)

1 概述

Redis的发布与订阅功能由PUBLISH、SUBSCRIBE、PSUBSCRIBE 等命令组成。
通过执行SUBSCRIBE命令,客户端可以订阅一个或多个频道,从而成为这些频道的订阅者( subscriber):每当有其他客户端向被订阅的频道发送消息( message)时,频道的所有订阅者都会收到这条消息。
举个例子,假设A、B、C三个客户端都执行了命令:

SUBSCRIBE "news. it"

那么,订阅关系将会是下边这个样子:
在这里插入图片描述
这时候某个客户端执行发布命令时,其他客户端就会收到消息:
在这里插入图片描述
除了订阅频道之外,客户端还可以通过执行PSUBSCRIBE命令订阅一个或多个模式,从而成为这些模式的订阅者:每当有其他客户端向某个频道发送消息时,消息不仅会被发送给这个频道的所有订阅者,它还会被发送给所有与这个频道相匹配的模式的订阅者。
也就是说在下图的例子中,向频道“news.it”发了消息客户端A C D 都会收到消息:
在这里插入图片描述
接下来我们来详细的讲解一下各个功能的实现:

2 频道的订阅与退订

当一个客户端执行SUBSCRIBE命令订阅某个或某些频道的时候,这个客户端与被订阅频道之间就建立起了一种订阅关系。
Redis将所有频道的订阅关系都保存在服务器状态的pubsub_channels字典里面,这个字典的键是某个被订阅的频道,而键的值则是个链表,链表里面记录了所有订阅这个频道的客户端,如下所示:

struct redisServer {
	// ...
	//保存所有频道的订阅关系
	dict *pubsub_ channels;
	// ...
};

在这里插入图片描述

2.1 订阅频道

每当客户端执行SUBSCRIBE命令订阅某个或某些频道的时候,服务器都会将客户端与被订阅的频道在pubsub_ channels 字典中进行关联。
简单来说就是在那个字典中,如果有对应的频道就追加当前的client,如果没有当前的频道就先创建当前的频道再追加,伪代码如下图所示:

def subscribe (*a11_input_channels) :
	#遍历输入的所有频道
	for channel in all_input_channels:
		#如果channel不存在于pubsub_channels字典(没有任何订阅者)
		#那么在字典中添加channel键,并设置它的值为空链表
		if channel not in server.pubsub_channels:
			server.pubsub_channels[channel] = []
		#将订阅者添加到频道所对应的链表的末尾
		server.pubsub_channels[channel].append(client)

2.2 退订频道

UNSUBSCRIBE命令的行为和SUBSCRIBE命令的行为正好相反,当一个客户端退订某个或某些频道的时候,服务器将从pubsub_ channels 中解除客户端与被退订频道之间的关联。
具体的和订阅逻辑正好相反,伪代码如下图所示:

def unsubscribe (*al1_input_channels) :
	#遍历要退订的所有频道
	for channel in all_input_channels:
		#在订阅者链表中删除退订的客户端
		server.pubsub_channels[channel].remove(client)
		#如果频道已经没有任何订阅者了(订阅者链表为空)
		#那么将频道从字典中删除
		if len(server.pubsub_channels[channel]) == 0:
			server.pubsub_channels.remove(channel)

3 模式的订阅与退订

前面说过,服务器将所有频道的订阅关系都保存在服务器状态的pubsub_channels属性里面,与此类似,服务器也将所有模式的订阅关系都保存在服务器状态的pubsub_patterns属性里面:

struct redisServer {
	//
	//保存所有模式订阅关系
	list *pubsub_ patterns;
	//
};

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

typedef struct pubsubPattern {
	//订阅模式的客户端
	redisClient *client;
	//被订阅的模式.
	robj *pattern;
} pubsubPattern;

在这里插入图片描述

3.1 订阅模式

每当客户端执行PSUBSCRIBE命令订阅某个或某些模式的时候,服务器会对每个被订阅的模式执行以下两个操作:
1)新建一个pubsubPattern结构,将结构的pattern属性设置为被订阅的模式,client属性设置为订阅模式的客户端。
2)将pubsubPattern结构添加到pubsub_ patterns 链表的表尾。
伪代码如下图所示:

def psubscribe (*a11_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)

3.2 退订模式

模式的退订命令PUNSUBSCRIBE是PSUBSCRIBE命令的反操作:当一个客户端退订某个或某些模式的时候,服务器将在pubsub_patterns 链表中查找并删除那些pattern属性为被退订模式,并且client属性为执行退订命令的客户端的pubsubPattern结构。伪代码如下:

def punsubscribe (*a1l_input_patterns) :
	#遍历所有要退订的模式
	for pattern in all_input_patterns:
		#遍历pubsub_ patterns链表中的所有pubsubPattern结构
		for pubsubPattern in server.pubsub_patterns: 
			#如果当前客户端和pubsubPattern记录的客户端相同
			#并且要退订的模式也和pubsubPattern记录的模式相同
			if client == pubsubPattern.client and \
				pattern == pubsubPattern.pattern:
				#那么将这个pubsubPattern从链表中删除
				server.pubsub_patterns.remove(pubsubPattern)

4-5

见博客 详解Redis —— 发布与订阅(下)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

从前慢慢慢死了

打钱!一分也行啊!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值