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

[经验分享] Redis

[复制链接]

尚未签到

发表于 2016-12-21 06:06:20 | 显示全部楼层 |阅读模式
一.设计模式-发布订阅模式
发布订阅模式,又叫观察者模式,属于四人帮的二十三个设计模式中的行为模式。”定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于他的对象都会得到通知并被自动更新“,模式UML如下图。
DSC0000.jpg
通俗一点可以理解为,Subject中保存了Observer的引用组成的列表。Subject状态变化时,遍历列表调用所有Observer的notify成员方法。
发布订阅模式应用场景很多,相当于在系统中构建一个简单的事件处理系统,部分编程语言(如java提供被观察者类java.util.Observable和观察者接口java.util.Observer)原生库中已包含观察者模式的简单实现。
二.Redis-PubSub介绍
Redis中的PubSub实现较上面复杂,但设计思想和上面一致。
客户端A发出一个订阅的频道名称(可以理解为attach A 到Subject)
subscribe  temperature  rainfall

其他客户端B发布消息(可以理解为B更新Subjec的状态)
publish  rainfall 350cc

A客户端将收到降雨量350cc这条message
客户端A也可以取消订阅频道(可以理解为A从Subjec中detach)
unsubscribe rainfall

DSC0001.png
在提供订阅频道外,Redis还提供了psubscribe/punsubscribe来订阅/取消订阅一个或多个模式。如果模式照通配符(glob)来匹配某个/ 某些频道,当有信息发送给这个/这些频道的时候, 客户端也会收到这个/这些频道的信息。

二.Redis-PubSub订阅频道

Redis中PubSub实现也比较简单,订阅频道的功能主要保存在字典中,其中key为频道,而value是redisClient组成的列表。
下图为订阅频道的redisServer的pubsub_channels字典示例,ClientA订阅 temperature和rainfall,ClientC订阅temperature
DSC0002.png
当客户端ClientD订阅已经存在的频道时,将ClientD加到该频道对应的链表的尾巴,如订阅rainfall频道。
当客户端ClientD订阅不存在的频道时,新建新频道的key及对应的链表,将ClientD加到新创建的链表中,下图为ClientD执行 subscribe snow后的字典示例。
DSC0003.png
当客户端ClientA取消订阅频道时,将客户端ClientA从对应的频道的链表中删除,如果删除后对应的频道无客户订阅,则将对应的频道的key从字典中删除。
如ClientA执行subscribe(无参数的subscribe 命令订阅的所有频道都会被退订)后字典的示例。
DSC0004.png
以上的所有操作在更新redisServer的pubsub_channels字典的同时也会更新redisClient中的pubsub_channels字典,redisClient的pubsub_channels保存着对应客户端订阅的频道。

四.Redis-PubSub订阅模式

订阅模式的功能保存在redisServer的pubsub_patterns链表中,链表的元素结构如下:
typedef struct pubsubPattern {
/*客户端信息,唯一确认一个客户连接*/
redisClient *client;
/*模式信息的字符串对象,如"*no*"*/
robj *pattern;
} pubsubPattern;

下图示例客户端ClientA 订阅“*it*”、"*eye*",客户端ClientB订阅"*eye*"的链表。
DSC0005.png
增加时遍历redisClient的pubsub_patterns链表,如果不存在,将新的模式增加到redisServer的pubsub_patterns链表的尾部。
删除时需要遍历redisClient的整个pubsub_patterns,如果存在,在定位redisServer的pubsub_patterns链表进行删除操作。
与订阅频道同样,在更新redisServer的pubsub_patterns链表的同时,也更新redisClient的pubsub_patterns链表,redisClient的pubsub_channels保存着对应客户端订阅的模式。
五.消息发送publish
当发送消息时,先从redisServer找到对应的频道的key所拥有的链表,遍历链表发送消息;然后遍历redisServer的pubsub_patterns链表,对频道和pattern进行匹配(stringmatch),如果适配将信息增加到客户端的返回中。
发送消息的伪代码如下:
/*
* 发送消息
* channel 频道
* message  消息主体
* */
function pubsubPublishMessage(channel,message){
/*需要channel被某些客户端订阅,如果不存在pubsub_channels中,就没有订阅此频道的客户*/
if (isset(server.pubsub_channels[channel])){
/*
* 遍历pubsub_channels中对应频道的订阅者的链表
* 给每个频道订阅者发布消息
* */
foreach (server.pubsub_channels[channel] as receiver){
sendMessage(receiver, message);
}
}
/*遍历模式订阅的链表*/
foreach (server . pubsub_patterns as pubsubPattern){
/*如果模式与频道适配,发送消息给此客户端*/
if (stringmatch(pubsubPattern.pattern, channel)) {
sendMessage(pubsubPattern.client, message);
}
}
}

从上面代码中可以Redis发布的消息“即发即失”,redis不会持久保存发布的消息, 一旦client端断开链接,将会失去部分消息。
如果需要client非常关注的消息(如用户支付订单成功,client发货),建议不要用Redis的PubSub功能,可以用其他专门的消息队列系统,也可用Redis的链表,然后客户端进行轮询。

运维网声明 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-316997-1-1.html 上篇帖子: 非诚勿扰聊天实现,tornado + redis 下篇帖子: 从hiredis使用出core谈谈redis多线程的使用
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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