设为首页 收藏本站
查看: 956|回复: 0

[经验分享] 《Redis源码学习笔记》发布/订阅

[复制链接]

尚未签到

发表于 2016-12-20 09:10:09 | 显示全部楼层 |阅读模式
《Redis源码学习笔记》文章列表
Redis的SUBSCRIBE命令,可以让客户端订阅任意数量的频道,每当有新消息发送到某个频道时,Redis就会把这消息发送给所有订阅该频道的客户端;如下图:客户端Client_1,Client_2,Client_3都订阅了频道channel,当有消息PUBLISH到频道channel时,这三个客户端都将收到消息:
DSC0000.png
原理:RedisServer内部维护了一个pubsub_channels字典,其中字典的键就是被订阅的频道,而键值就是订阅该频道的客户端列表;
DSC0001.png
这样,当一个客户端执行PUBLISH channel_name命令时,Redis就可以根据channel_name在pubsub_channels中找到与其关联的客户端列表,然后把消息发送给它们,伪代码;
def publishCommand(channel, msg):
# 获取订阅channel的所有客户端列表
client_list = redisServer.pubsub_channels.get(channel)
if client_list is None: return
# 向每个客户端发送消息
for client in client_list:
client.sendMessage(msg)
另外,客户端自己也维护了一个pubsub_channels属性,用来记录自己订阅了哪些频道;同watched_keys属性一样(详情请参看 事务章节),客户端维护这些也是出于效率考虑的:
a. 防止订阅相同的频道;
def subscribeCommand(client, channels):
for ch in channels:
# 如果已经订阅了该频道,则跳过
if ch  in client.pubsub_channels: continue
# 把client添加到该频道关联的客户端列表
client_list = redisServer.pubsub_channels.get(ch)
client_list.add(client)
client.pubsub_channels.add(ch)
b. 在UNSUBSCRIBE时,可以快捷的取消该客户端订阅的所有频道,而无需遍历整个redisServer.pubsub_channels字典,伪代码:
def unsubscribeCommand(client):
# 获取client订阅的所有频道
channels = client.pubsub_channels
# 遍历频道
for ch in channels:
client_list = redisServer.pubsub_channels(ch)  
# 从该频道关联的客户端列表中,删除client
client_list.del(client)
client.pubsub_channels.del(ch)

考虑这么一个需求:有两个频道,名字都以“hello_开头”,分别叫做hello_1, hello_2;当我们要订阅这类频道时,我们可能会这么写:SUBSCRIBE hello_1 hello_2,但是如果有100个难道要这样写 SUBSCRIBE hello_1 hello_2 ... hello_100? 这时候我们可以使用“模式订阅”命令PSUBSCRIBE, 譬如这里我们就可以写成,PSUBSCRIBE hello_* ;这样,当一个客户端执行PUBLISH命令时,redis不仅会把消息发送给所有订阅该频道的客户端列表,同时也会把该频道与所有模式匹配,如果匹配成功,则把消息同样发送给订阅该模式的客户端列表:
DSC0002.png
所以完整的PUBLISH命令伪代码如下:
def publishCommand(channel, msg):
# 获取订阅channel的所有客户端列表
client_list = redisServer.pubsub_channels.get(channel)
if client_list is None: return
# 向每个客户端发送消息
for client in client_list:
client.sendMessage(msg)
# 遍历pubsub_patterns
for pattern, client in redisServer.pubsub_patterns:
# 若模式与channel匹配,则把消息发送给订阅该模式的客户端
if pattern.match(channel):
client.sendMessage(msg)
更多细节请看:pubsub.c/publishCommand函数
总结:
1. 熟悉发布订阅相关命令:subscribe/unsubscribe psubscribe/punsubscribe publish;
2. 了解发布订阅实现原理;

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-316767-1-1.html 上篇帖子: redis作为消息队列的使用 下篇帖子: Redis Hash 的 HSET、HGET、HMSET、HMGET 性能测试
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表