草庐IT

图解redis发布和订阅

编程界的谢菲尔德 2023-06-14 原文

目录

1.什么是发布订阅

1.1概念

1.2发布订阅过程

1.3发布订阅分为两类

2. 频道的订阅与退订

2.1subcribe

2.2退订频道

3. 模式的订阅和退订

3.1模式的订阅

3.2punsubscribe

4.频道和模式的发布

4.1频道的发布

4.2模式的发布


1.什么是发布订阅

1.1概念

1.发布订阅模式又叫观察者模式,是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
2.主要的目的是解耦消息发布者和消息订阅者之间的耦合,这点和设计模式中的观察者模式比较相似。
3.由三部分组成:发布者(pub),订阅者(sub)和频道(channel)
4.Redis 客户端可以订阅任意数量的频道。
5.Redis 在订阅者和发布者之间起到了消息路由的功能。

1.2发布订阅过程

当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端

1.3发布订阅分为两类

 1.频道的发布订阅

 2.模式的发布订阅

2. 频道的订阅与退订

2.1subcribe

当一个客户端执行SUBSCRIBE命令订阅某个或某些频道的时候, 这个客户端与被订阅频道之间就建立起了一种订阅关系

格式  SUBSCRIBE channel [channel …]

底层原理 :

1.pubsub_channels字典 

Redis将所有频道的订阅关系都保存在服务器状态

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

图形示意:

client-1、client-2、client-3三个客户端正在订阅"news.it"频道。

·客户端client-4正在订阅"news.sport"频道。

·client-5和client-6两个客户端正在订阅"news.business"频道。

 2.情况分类

1.如果频道已经有其他订阅者,那么它在pubsub_channels字典中必 然有相应的订阅者链表,程序唯一要做的就是将客户端添加到订阅者链 表的末尾。

2·如果频道还未有任何订阅者,那么它必然不存在于 pubsub_channels字典,程序首先要在pubsub_channels字典中为频道创建 一个键,并将这个键的值设置为空链表,然后再将客户端添加到链表, 成为链表的第一个元素

图形示意

SUBSCRIBE "news.sport" "news.movie”

1. ·更新后的pubsub_channels字典新增了"news.movie"键,该键对应的 链表值只包含一个client-10086节点,表示目前只有client-10086一个客户 端在订阅"news.movie"频道

2.至于原本就已经有客户端在订阅的"news.sport"频道,client-10086 的节点放在了频道对应链表的末尾

2.2退订频道

格式 unsub channel message

底层原理:

UNSUBSCRIBE命令的行为和SUBSCRIBE命令的行为正好相反, 当一个客户端退订某个或某些频道的时候,服务器将从pubsub_channels 中解除客户端与被退订频道之间的关联

图形示意:

·程序会根据被退订频道的名字,在pubsub_channels字典中找到频 道对应的订阅者链表,然后从订阅者链表中删除退订客户端的信息。

·如果删除退订客户端之后,频道的订阅者链表变成了空链表,那 么说明这个频道已经没有任何订阅者了,程序将从pubsub_channels字典 中删除频道对应的键

执行之后 

UNSUBSCRIBE "news.sport" "news.movie"

 

3. 模式的订阅和退订

3.1模式的订阅

1.psubscribe命令

  • 格式: PSUBSCRIBE pattern [pattern …]

  • eg : PSUBSCRIBE China* 订阅以China为开头的所有频道

  • 底层原理

  • 1.redisServer.pubsub_patterns 属性是一个链表,链表中保存着所有和模式相关的信息:

    2.链表中的每个节点都包含一个 redis.h/pubsubPattern 结构:

    3.client 属性保存着订阅模式的客户端,而 pattern 属性则保存着被订阅的模式。

    4.每当调用 PSUBSCRIBE 命令订阅一个模式时,程序就创建一个包含客户端信息和被订阅模式的 pubsubPattern 结构,并将该结构添加到redisServer.pubsub_patterns 链表中

    举个例子,下图展示了一个包含两个模式的 pubsub_patterns 链表, 其中 client123 和 client256 都正在订阅 tweet.shop.* 模式

  • 如果这时客户端 client10086 执行 PSUBSCRIBE broadcast.list.* , 么 pubsub_patterns 链表将被更新成这样:

  •  

 note1

假设客户端同时订阅了某种模式和符合该模式的某个频道,那么发送给这个频道的消息将被客户端接收到两次,只不过这两条消息的类型不同,一个是message类型,一个是pmessage类型,但其内容相同

3.2punsubscribe

格式: PUNSUBSCRIBE [pattern [pattern …]]

原理:这个命令执行的是订阅模式的反操作:程序会删除redisServer.pubsub_patterns 链表中,所有和被退订模式相关联的 pubsubPattern 结构,这样客户端就不会再收到和模式相匹配的频道发来的信息。

note1 1.在SUBSCRIBE,PSUBSCRIBE,UNSUBSCRIBE和PUNSUBSCRIBE命令中,其返回值都包含了该客户端当前订阅的频道和模式的数量,当这个数量变为0时,该客户端会自动退出订阅状态。

2.PUBLISH和SUBSCRIBE的缺陷在于客户端必须一直在线才能接收到消息,断线可能会导致客户端丢失消息,除此之外,旧版的redis可能会由于订阅者消费不够快而变的不稳定导致崩溃,甚至被管理员杀掉

4.频道和模式的发布

4.1频道的发布

命令 PUSHLISH<channel><message>

因为服务器状态中的pubsub_channels字典记录了所有频道的订阅关 系,所以为了将消息发送给channel频道的所有订阅者,PUBLISH命令 要做的就是在pubsub_channels字典里找到频道channel的订阅者名单(一 个链表),然后将消息发送给名单上的所有客户端

例子1

PUBLISH "news.it" "hello"

那么PUBLISH命令将在pubsub_channels字典中查找键"news.it"对应 的链表值,并通过遍历链表将消息"hello"发送给"news.it"频道的三个订 阅者:client-1、client-2和client-3。

4.2模式的发布

发送信息到模式的工作也是由 PUBLISH 命令进行的。PUBLISH 除了将 message 发送到所有订阅 channel 的客户端之外,它还会将 channel 和 pubsub_patterns 中的模式进行对比,如果 channel 和某个模式匹配的话,那么也将 message 发送到订阅那个模式的客户端
 

eg.下图展示了一个带有频道和模式的例子, 其中 tweet.shop.* 模式匹配了tweet.shop.kindle 频道和 tweet.shop.ipad 频道, 并且有不同的客户端分别订阅它们三个

当有信息发送到 tweet.shop.kindle 频道时, 信息除了发送给 clientX 和 clientY 之外, 还会发送给订阅 tweet.shop.* 模式的 client123 和 client256 

 

有关图解redis发布和订阅的更多相关文章

  1. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  2. ruby-on-rails - 如何在发布新的 Ruby 或 Rails 版本时收到通知? - 2

    有人知道在发布新版本的Ruby和Rails时收到电子邮件的方法吗?他们有邮件列表,RubyonRails有一个推特,但我不想听到那些随之而来的喧嚣,我只想知道什么时候发布新版本,尤其是那些有安全修复的版本。 最佳答案 从therailsblog获取提要.http://weblog.rubyonrails.org/feed/atom.xml 关于ruby-on-rails-如何在发布新的Ruby或Rails版本时收到通知?,我们在StackOverflow上找到一个类似的问题:

  3. ruby-on-rails - 获取 ActionController::RoutingError(当尝试使用 AngularJS 将数据发布到 Rails 服务器时,没有路由匹配 [OPTIONS] "/users" - 2

    尝试从我的AngularJS端将数据发布到Rails服务器时出现问题。服务器错误:ActionController::RoutingError(Noroutematches[OPTIONS]"/users"):actionpack(4.1.9)lib/action_dispatch/middleware/debug_exceptions.rb:21:in`call'actionpack(4.1.9)lib/action_dispatch/middleware/show_exceptions.rb:30:in`call'railties(4.1.9)lib/rails/rack/logg

  4. iNFTnews | 周杰伦18年前未发布的作品Demo,藏在了区块链技术里 - 2

    当音乐碰上区块链技术,会擦出怎样的火花?或许周杰伦已经给了我们答案。8月29日下午,B站独家首发周杰伦限定珍藏Demo独家访谈VCR,周杰伦在VCR里分享了《晴天》《青花瓷》《搁浅》《爱在西元前》四首经典歌曲Demo背后的创作故事,并首次公布18年前未发布的神秘作品《纽约地铁》的Demo。在VCR中,方文山和杰威尔音乐提及到“多亏了区块链技术,现在我们可以将这些Demos,变成独一无二具有收藏价值的艺术品,这些Demos可以在薄盒(国内数藏平台)上听到。”如何将音乐与区块链技术相结合,薄盒方面称:“薄盒作为区块链技术服务方,打破传统对于区块链技术只能作为数字收藏的理解。聚焦于区块链技术赋能,在

  5. ruby - 如何在 Ruby 中从内存中 HTTP 发布流数据? - 2

    我想上传我在运行时用Ruby生成的数据,就像从block中提供上传数据一样。我找到的所有示例仅展示了如何流式传输必须在请求之前位于磁盘上的文件,但我不想缓冲该文件。除了滚动我自己的套接字连接之外,最好的解决方案是什么?这是一个伪代码示例:post_stream('127.0.0.1','/stream/')do|body|generate_xmldo|segment|body 最佳答案 有效的代码。require'thread'require'net/http'require'base64'require'openssl'class

  6. IDEA 2023.1 正式发布,新特性简介 - 2

     昨晚看到IDEA官推宣布IntelliJIDEA2023.1正式发布了。简单看了一下,发现这次的新版本包含了许多改进,进一步优化了用户体验,提高了便捷性。至于是否升级最新版本完全是个人意愿,如果觉得新版本没有让自己感兴趣的改进,完全就不用升级,影响不大。软件的版本迭代非常正常,正确看待即可,不持续改进就会慢慢被淘汰!根据官方介绍:IntelliJIDEA2023.1针对新的用户界面进行了大量重构,这些改进都是基于收到的宝贵反馈而实现的。官方还实施了性能增强措施,使得Maven导入更快,并且在打开项目时IDE功能更早地可用。由于后台提交检查,新版本提供了简化的提交流程。IntelliJIDEA

  7. Unity数据可视化图表插件XCharts3.0发布 - 2

    Unity数据可视化图表插件XCharts3.0发布历时8个多月,业余时间,断断续续,XCharts3.0总算发布了。如果要打个满意度,我给3.0版本来个80分。对于代码框架结构设计的调整改动,基本符合预期,甚是满意。相比之前的1.0和2.0版本,我认为3.0才是一个拿得出手给广大开发者使用的版本。1.0发布的时候,很兴奋,从0.1到1.0,也磨了一年,真的等不及想给大家试用了,还特地写过一篇文章以示庆祝。那个时候,1.0虽然还还不够完善,功能也不够丰富,但它是XCharts的开始,没有1.0,也就没有后面的2.0和3.0。后面的2.0发布,做了很多改进和优化,随着版本迭代,慢慢的发现有不少硬

  8. ruby-on-rails - 无法使用 Stripe 保存或取消订阅 - 2

    将stripe的API与RubyonRails结合使用我无法保存订阅。我能够检索、更新和保存客户对象:customer=Stripe::Customer.retrieve(some_customer_id)#thisworkscustomer.save#thisworks我还可以检索订阅:subscription=customer.subscriptions.retrieve("some_subscription_id")#这个有效但是,在尝试保存订阅时:subscription.save#这不起作用我不断得到这个:NoMethodError:undefinedmethod`save'

  9. ruby-on-rails - 在 Rails 中是否有比 Observers 更直接的方式来执行发布/订阅模式? - 2

    我有一个模型依赖于一个单独的、联合的模型。classMagazine图像是多态的,可以附加到许多对象(页面和文章),而不仅仅是杂志。杂志需要在相关图像发生任何变化时自行更新该杂志还保存了一张自己的截图,可用于宣传:classMagazine现在如果图像发生变化,杂志也需要更新其截图。所以杂志真的需要知道图片什么时候出了问题。所以我们可以天真地直接从封面图片触发屏幕截图更新classImage...但是图片不应该代表杂志做事然而,图片可以用于许多不同的对象,实际上不应该对杂志进行特定的操作,因为这不是图片的责任。该图像也可能附加到页面或文章,并且不需要为它们做各种事情。“正常”的rail

  10. ruby-on-rails - 在 ActionCable 中找不到订阅类 'MyChannel' - 2

    我在使用ActionCable时遇到问题,每当我运行我的程序时,我都会收到一条错误消息,提示SubscriptionClassnotfoundConversationChannel当我尝试发送消息时,我得到了这个日志SuccessfullyupgradedtoWebSocket(REQUEST_METHOD:GET,HTTP_CONNECTION:Upgrade,HTTP_UPGRADE:websocket)Subscriptionclassnotfound:"ConversationChannel"Couldnotexecutecommandfrom{"command"=>"mess

随机推荐