企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
基于模式的发布与订阅实现方式主要通过以下三个命令: * `psubscribe pattern-1 pattern-2`:订阅一个或者多个模式,模式可以通过通配符`?`和`*`来表示。 * `pubsubscribe pattern-1 pattern-1`:取消模式的订阅(基于命令操作,界面上无法退订) * `publish channel-1 message`:向频道`channel-1`发送消息`message`。这里和上面基于频道命令是一样的。 打开一个客户端一,输入订阅命令`psubscribe m*`,表示当前客户端订阅了所有以`m`开头的频道: ![](https://img.kancloud.cn/5e/e2/5ee28d224bee0574042ad4c88726c888_588x127.png) 然后再打开一个客户端二,执行以下发布消息命令: ~~~sql publish movie myCountry //发布消息 myCountry 到 movie 频道 publish music love //发布消息 love 到 music 频道 publish tv myHome //发布消息 myHome 到 tv 频道 ~~~ ![](https://img.kancloud.cn/50/38/5038121c22423329add70183b1fb5502_586x137.png) 前面两个频道发布之后返回`1`就表示当前有`1`个客户端订阅了该频道(上面基于频道订阅的客户端关闭之后会自动取消订阅,如果没有关闭的话这里前面两个就会返回`2`),消息已经发送到这个客户端。 这时候我们再回到之前的客户端一,就会发现客户端一收到了`myCountry`和`love`两条消息,因为这两个频道都是以`m`开头的,而`myHome`这条消息是属于频道`tv`,并不是以`m`开头,客户端一并没有订阅,故而不会收到: ![](https://img.kancloud.cn/72/85/7285044bc3f0d45170e86727af37101b_587x228.png) 同样的,基于模式的订阅也提供了一个查询命令: * `pubsub numpat`:查询当前服务器被订阅模式的数量。 #### 实现原理分析 客户端与其订阅的模式信息被保存在`redisServer`对象中的`pubsub_patterns`属性中: ~~~c struct redisServer { list pubsub_patterns;//保存了客户端及其订阅的模式信息 //...省略其他信息 }; ~~~ `pubsub_patterns`属性是一个列表,其列表内结构(源码`serer.h`内)定义如下: ~~~c typedef struct pubsubPattern { client *client;//订阅模式的客户端 robj *pattern;//被订阅的模式 } pubsubPattern; ~~~ ![](https://img.kancloud.cn/54/a4/54a42f5f0ba0c31c0bbc1f019c6521f4_722x179.png) * 订阅:新建一个`pubsubPattern`数据结构加入到链表`pubsub_patterns`的结尾。 * 取消订阅:从链表中将当前取消订阅的客户端`pubsubPattern`从链表`pubsub_patterns`中移除。 * 发送消息:此时需要遍历整个链表来寻找能匹配的模式。之所以基于模式场景使用链表是因为模式支持通配符,所以没有办法直接用字典实现。 PS:当基于频道和基于模式两种订阅同时都存在时,`Redis`会先去寻找频道字典,再去遍历模式链表进行消息发送。