04、模式订阅结构
模式渠道的订阅与单个渠道的订阅类似,不过服务器是将所有模式的订阅关系都保存在服务器状态的pubsub_patterns
属性里面。
struct redisServer{ //保存所有模式订阅关系 list *pubsub_patterns; }
与订阅单个 Channel 不同的是,pubsub_patterns 属性是一个链表,不是字典。节点的结构如下:
struct pubsubPattern{ //订阅模式的客户端 redisClient *client; //被订阅的模式 robj *pattern; } pubsubPattern;
其实 client
属性是用来存放对应客户端信息,pattern
是用来存放客户端对应的匹配模式。
所以对应上面的 Client-06 模式匹配的结构存储如下
在pubsub_patterns
链表中有一个节点,对应的客户端是 Client-06,对应的匹配模式是run*
。
4.1、订阅模式
当某个客户端通过命令psubscribe
订阅对应模式的 Channel 时候,服务器会创建一个节点,并将 Client 属性设置为对应的客户端,pattern 属性设置成对应的模式规则,然后添加到链表尾部。
对应的伪代码如下:
List<PubSubPattern> pubsub_patterns = new ArrayList<>(); public void psubscribe(String[] subscribeList, Object client) { //遍历所有订阅的 channel,创建节点 for (int i = 0; i < subscribeList.length; i++) { PubSubPattern pubSubPattern = new PubSubPattern(); pubSubPattern.client = client; pubSubPattern.pattern = subscribeList[i]; pubsub_patterns.add(pubSubPattern); } }
- 创建新节点;
- 给节点的属性赋值;
- 将节点添加到链表的尾部;
4.2、退订模式
退订模式的命令是punsubscribe
,客户端使用这个命令来退订一个或者多个模式 Channel。服务器接收到该命令后,会遍历pubsub_patterns
链表,将匹配到的 client 和 pattern 属性的节点给删掉。这里需要判断 client 属性和 pattern 属性都合法的时候再进行删除。
伪代码如下:
public void punsubscribe(String[] subscribeList, Object client) { //遍历所有订阅的 channel 相同 client 和 pattern 属性的节点会删除 for (int i = 0; i < subscribeList.length; i++) { for (int j = 0; j < pubsub_patterns.size(); j++) { if (pubsub_patterns.get(j).client == client && pubsub_patterns.get(j).pattern == subscribeList[i]) { remove(pubsub_patterns); } } } }
遍历所有的节点,当匹配到相同 client 属性和 pattern 属性的时候就进行节点删除。
05、发布消息
发布消息比较好容易理解,当一个客户端执行了publish channelName message
命令的时候,服务器会从pubsub_channels
和pubsub_patterns
两个结构中找到符合channelName
的所有 Channel,进行消息的发送。在 pubsub_channels
中只要找到对应的 Channel 的 key 然后向对应的 value 链表中的客户端发送消息就好。
06、总结
这篇文章主要给大家介绍了一下 Redis 的发布/订阅的使用方式和底层的存储结构以及部分伪代码的实现,希望对大家有帮助。
-end-
好了各位读者朋友们,以上就是本文的全部内容了。能看到这里的都是最优秀的程序员,我们必须要伸出骄傲的大拇指为你点个赞👍。如果觉得不过瘾,还想看到更多,再给大家推荐几篇。
面试必问之 ConcurrentHashMap 线程安全的具体实现方式
日常操作来了!如果觉得这篇文章有点用的话,求在看、求转发,明人不说暗话,我们喜欢这种被大家伙宠爱的感觉。
one more thing!如果大家想要在最短的时间内成为一名 Java 大神,可以扫描下方的二维码,加入我们的知识星球。我们下篇文章见!