Redis设计与实现之订阅与发布

目录

一、 订阅与发布

1、 频道的订阅与信息发送

2、订阅频道

3、发送信息到频道

4、 退订频道

5、模式的订阅与信息发送

​编辑 6、 订阅模式

7、 发送信息到模式

8、 退订模式

三、订阅消息断连

1、如果订阅者断开连接了,再次连接会不会丢失之前发布的消息?

2、订阅者是否需要一直保持连接状态才能接收到发布者的消息?

3、订阅与发布的消息会被持久化吗?

四、订阅频道来源

1、如果一个订阅者订阅了多个频道,如何判断收到的消息是来自哪个频道的?

2、是否可以在Redis中实现多个订阅者同时订阅同一个频道?

3、是否可以在Redis中实现多个发布者同时发布消息到同一个频道?

4、如何停止订阅某个频道的消息?

5、是否可以取消订阅所有频道的消息?

五、订阅与发布的功能在Redis集群中是否可用?

六、、小结


一、 订阅与发布

Redis 通过 PUBLISH 、SUBSCRIBE 等命令实现了订阅与发布模式,这个功能提供两种信息 机制,分别是订阅/发布到频道和订阅/发布到模式,下文先讨论订阅/发布到频道的实现,再讨 论订阅/发布到模式的实现。

1、 频道的订阅与信息发送

Redis 的 SUBSCRIBE 命令可以让客户端订阅任意数量的频道,每当有新信息发送到被订阅的频道时,信息就会被发送给所有订阅指定频道的客户端。
作为例子,下图展示了频道 channel1 ,以及订阅这个频道的三个客户端——client2 、client5 和 client1 之间的关系:

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

 在后面的内容中,我们将探讨 SUBSCRIBE 和 PUBLISH 命令的实现,以及这套订阅与发布 机制的运作原理。

2、订阅频道

每个 Redis 服务器进程都维持着一个表示服务器状态的 redis.h/redisServer 结构,结构的pubsub_channels 属性是一个字典,这个字典就用于保存订阅频道的信息:

struct redisServer { // ...
    dict *pubsub_channels;
// ...
};

其中,字典的键为正在被订阅的频道,而字典的值则是一个链表,链表中保存了所有订阅这个 频道的客户端。

比如说,在下图展示的这个 pubsub_channels 示例中,client2 、client5 和 client1 就订 阅了 channel1 ,而其他频道也分别被别的客户端所订阅:

当客户端调用 SUBSCRIBE 命令时,程序就将客户端和要订阅的频道在 pubsub_channels 字 典中关联起来。

举个例子,如果客户端 client10086 执行命令 SUBSCRIBE channel1 channel2 channel3 , 那么前面展示的 pubsub_channels 将变成下面这个样子:

 SUBSCRIBE 命令的行为可以用伪代码表示如下:

def SUBSCRIBE(client, channels): 
    # 遍历所有输入频道
    for channel in channels:
    # 将客户端添加到链表的末尾 
    redisServer.pubsub_channels[channel].append(client)

通过 pubsub_channels 字典,程序只要检查某个频道是否字典的键,就可以知道该频道是否正 在被客户端订阅;只要取出某个键的值,就可以得到所有订阅该频道的客户端的信息。

3、发送信息到频道

了解了 pubsub_channels 字典的结构之后,解释 PUBLISH 命令的实现就非常简单了:当调 用 PUBLISH channel message 命令,程序首先根据 channel 定位到字典的键,然后将信息发 送给字典值链表中的所有客户端。

比如说,对于以下这个 pubsub_channels 实例,如果某个客户端执行命令 PUBLISH channel1 "hello moto" ,那么 client2 、client5 和 client1 三个客户端都将接收到 "hello moto" 信息:

PUBLISH 命令的实现可以用以下伪代码来描述:

def PUBLISH(channel, message):
    # 遍历所有订阅频道 channel 的客户端
    for client in server.pubsub_channels[channel]:
    # 将信息发送给它们 
    send_message(client, message)

4、 退订频道

使用 UNSUBSCRIBE 命令可以退订指定的频道,这个命令执行的是订阅的反操作:它从 pubsub_channels 字典的给定频道(键)中,删除关于当前客户端的信息,这样被退订频道的 信息就不会再发送给这个客户端。

5、模式的订阅与信息发送

当使用 PUBLISH 命令发送信息到某个频道时,不仅所有订阅该频道的客户端会收到信息,如 果有某个/某些模式和这个频道匹配的话,那么所有订阅这个/这些频道的客户端也同样会收到 信息。

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

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

 

 另一方面,如果接收到信息的是频道 tweet.shop.ipad ,那么 client123 和 client256 同样 会收到信息:

 6、 订阅模式

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

struct redisServer { // ...
    list *pubsub_patterns;
// ...
};

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

typedef struct pubsubPattern { 
    redisClient *client;
    robj *pattern;
} pubsubPattern;

client 属性保存着订阅模式的客户端,而 pattern 属性则保存着被订阅的模式。
每当调用 PSUBSCRIBE 命令订阅一个模式时,程序就创建一个包含客户端信息和被订阅模式的

pubsubPattern 结构,并将该结构添加到 redisServer.pubsub_patterns 链表中。 作为例子,下图展示了一个包含两个模式的 pubsub_patterns 链表,其中 client123 和

client256 都正在订阅 tweet.shop.* 模式:

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

通过遍历整个 pubsub_patterns 链表,程序可以检查所有正在被订阅的模式,以及订阅这些模 式的客户端。

7、 发送信息到模式

发送信息到模式的工作也是由 PUBLISH 命令进行的,在前面讲解频道的时候,我们给出了这样一段伪代码,说它定义了 PUBLISH 命令的行为:

def PUBLISH(channel, message):
    # 遍历所有订阅频道 channel 的客户端
    for client in server.pubsub_channels[channel]:
        # 将信息发送给它们 
        send_message(client, message)

 但是,这段伪代码并没有完整描述 PUBLISH 命令的行为,因为 PUBLISH 除了将 message 发 送到所有订阅 channel 的客户端之外,它还会将 channel 和 pubsub_patterns 中的模式进行 对比,如果 channel 和某个模式匹配的话,那么也将 message 发送到订阅那个模式的客户端。

完整描述 PUBLISH 功能的伪代码定于如下:

def PUBLISH(channel, message):
    # 遍历所有订阅频道 channel 的客户端
    for client in server.pubsub_channels[channel]: 
        # 将信息发送给它们
        send_message(client, message)
    # 取出所有模式,以及订阅模式的客户端
    for pattern, client in server.pubsub_patterns:
        # 如果 channel 和模式匹配
        if match(channel, pattern):
            # 那么也将信息发给订阅这个模式的客户端 
            send_message(client, message)

举个例子,如果 Redis 服务器的 pubsub_patterns 状态如下: 

那么当某个客户端发送信息 "Amazon Kindle, $69." 到 tweet.shop.kindle 频道时,除了所 有订阅了 tweet.shop.kindle 频道的客户端会收到信息之外,客户端 client123 和 client256 也同样会收到信息,因为这两个客户端订阅的 tweet.shop.* 模式和 tweet.shop.kindle 频道 匹配。

8、 退订模式

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

三、订阅消息断连

1、如果订阅者断开连接了,再次连接会不会丢失之前发布的消息?

Redis的消息订阅-发布模式中,如果订阅者断开连接,再次连接时会丢失之前发布的消息。 Redis的发布-订阅机制是一种消息通信模式,新的订阅者只能接收到自连接之后发布的新消息,而不能获取到之前发布的消息。

2、订阅者是否需要一直保持连接状态才能接收到发布者的消息?

是的,订阅者需要一直保持连接状态才能接收到发布者的消息。当订阅者与Redis服务器建立连接后,它会发送SUBSCRIBE命令来订阅一个或多个频道。然后,Redis服务器会将该订阅者添加到被订阅频道的订阅列表中。当有新的消息发布到被订阅的频道时,Redis服务器会将消息发送给所有已订阅的订阅者。因此,如果订阅者断开连接或关闭,它将无法接收到后续的消息。为了保持订阅者的连接状态,可以使用长连接或心跳机制来定期发送PING命令给Redis服务器,以保持连接活跃。

3、订阅与发布的消息会被持久化吗?

Redis订阅与发布的消息默认是不会被持久化的。当一个客户端订阅了一个频道后,一旦该客户端与服务端断开连接,它之前订阅的消息就会丢失。同样地,当一个客户端发布一条消息后,如果没有其他客户端订阅该频道,那么该消息也会丢失。

不过,你可以使用Redis的持久化功能,如RDB快照和AOF日志,来实现将订阅与发布的消息持久化。通过配置Redis的持久化选项,你可以定期保存数据库中的数据到磁盘(RDB快照),或者将每个写操作追加到一个日志文件(AOF日志)。这样,即使Redis服务器重新启动,之前发布的消息也可以被恢复。

需要注意的是,Redis的持久化功能会对性能造成一定的影响,并且AOF日志相对于RDB快照来说更加耗费磁盘空间。因此,你需要根据自己的需求来选择合适的持久化方式。

四、订阅频道来源

1、如果一个订阅者订阅了多个频道,如何判断收到的消息是来自哪个频道的?

在Redis中,当一个订阅者订阅多个频道时,收到的消息会包含频道名和消息内容两部分。你可以通过解析收到的消息来判断消息来自哪个频道。

以下是一个示例订阅多个频道并解析消息的代码片段:

import redis

def process_message(channel, message):
    print("Received message from channel: %s, Message: %s" % (channel, message))

# 创建Redis连接
r = redis.Redis()

# 创建订阅对象
p = r.pubsub()

# 订阅多个频道
p.subscribe('channel1', 'channel2', 'channel3')

# 循环接收消息
for message in p.listen():
    # 解析消息
    if message['type'] == 'message':
        channel = message['channel']
        message_data = message['data']

        # 处理消息
        process_message(channel, message_data)

在上述示例中,首先创建了一个Redis连接,然后通过pubsub()方法创建了一个订阅对象p。接着使用subscribe()方法订阅了多个频道。

在循环中,通过listen()方法来接收消息。接收到的消息是一个字典,其中包含typechanneldata等字段。通过读取channel字段就可以判断消息来自哪个频道。

最后,你可以在process_message()函数中处理消息,例如打印消息内容或执行其他操作。

2、是否可以在Redis中实现多个订阅者同时订阅同一个频道?

是的,Redis可以实现多个订阅者同时订阅同一个频道。当有消息发布到这个频道时,所有订阅者都会接收到这条消息。

3、是否可以在Redis中实现多个发布者同时发布消息到同一个频道?

是的,Redis 支持多个发布者同时发布消息到同一个频道。当有多个客户端连接到 Redis 服务器,并且同时向同一个频道发布消息时,Redis 会将所有消息发送给订阅该频道的所有订阅者。无论发布者的数量有多少,Redis 都会将消息按照发布顺序逐个发送给所有订阅者。

4、如何停止订阅某个频道的消息?

在Redis中,要停止订阅某个频道的消息,需要使用UNSUBSCRIBE命令。

以下是停止订阅单个频道的示例:

UNSUBSCRIBE channel_name

如果你想停止订阅多个频道,可以使用以下命令:

UNSUBSCRIBE channel_name1 channel_name2 ...

请注意,当没有活动的订阅时,Redis连接将自动进入发布/订阅模式之外的模式。

5、是否可以取消订阅所有频道的消息?

是的,Redis可以取消订阅所有频道的消息。您可以使用UNSUBSCRIBE命令来取消订阅所有频道的消息。命令如下:

UNSUBSCRIBE

执行这个命令后,Redis将取消订阅当前连接已订阅的所有频道的消息。

五、订阅与发布的功能在Redis集群中是否可用?

订阅和发布功能在Redis集群中是可用的,但是有一些限制。在Redis集群中,只有一个节点可以执行写入操作,而其他节点只能执行读取操作。这意味着只有一个节点可以用于发布消息,而其他节点只能用于订阅消息。

在Redis集群中,订阅和发布的消息只能在同一个节点上进行,无法在多个节点之间传递。这是因为Redis集群中的不同节点具有不同的数据分片,并且消息的处理只能在具有相应数据分片的节点上进行。

要使用订阅和发布功能,在Redis集群中,您需要将订阅和发布的操作都发送到具有相同数据分片的节点上。您可以使用Redis的客户端库,在代码中明确指定发送到哪个节点。或者,您可以使用Redis的代理或消息中间件,将订阅和发布的操作转发到正确的节点。

总之,订阅和发布功能在Redis集群中是可用,但需要注意节点分片和消息处理的限制。

六、、小结

• 订阅信息由服务器进程维持的redisServer.pubsub_channels字典保存,字典的键为被 订阅的频道,字典的值为订阅频道的所有客户端。

• 当有新消息发送到频道时,程序遍历频道(键)所对应的(值)所有客户端,然后将消息 发送到所有订阅频道的客户端上。

• 订阅模式的信息由服务器进程维持的redisServer.pubsub_patterns链表保存,链表的 每个节点都保存着一个 pubsubPattern 结构,结构中保存着被订阅的模式,以及订阅该 模式的客户端。程序通过遍历链表来查找某个频道是否和某个模式匹配。

• 当有新消息发送到频道时,除了订阅频道的客户端会收到消息之外,所有订阅了匹配频 道的模式的客户端,也同样会收到消息。

• 退订频道和退订模式分别是订阅频道和订阅模式的反操作

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/254497.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

儿童玩具行业分析:发展态势良好,市场空间不断拓展

玩具是有利于促进幼儿体、德、智、美的全面发展;符合儿童年龄特征,能满足其好奇心、好动和探索活动的愿望;造型优美,反映事物的典型特征;活动多变,有助于鼓励学习。中国玩具产品包括毛绒玩具、塑胶玩具、纸质玩具、电子玩具、木制玩具、金属玩…

抖音网红的各种变现办法

抖音作为一款风靡全球的短视频平台,不仅为用户带来了娱乐和社交的乐趣,也为一些优秀的内容创作者提供了机会,成为了网红。而成为抖音网红不仅仅是一种荣誉,更是一种潜在的经济收入来源。在这篇文章中,我将介绍一些抖音…

气泡水机市场调研: 2023年行业消费需求及发展前景分析

气泡水机用于制作气泡水的机器,隶属于家电产业。在欧美等发达国家早已普遍使用,中国仅台湾等开放发达地方盛行。在中国大陆较为少见,近两年以健康环保产品形象兴起,市场饱和度不高。 中国气泡水机首次出现在中国市场是2012年&a…

小红书kop营销策略有哪些,达人投放总结!

从kol到koc,当今时代产品种草模式,层出不穷。品牌想要跟上市场更新迭代的洪流,就需要时刻了解新型的营销方式。那么对于新型的kop模式你了解多少呢?我们今天就将详细分享小红书kop营销策略有哪些,达人投放总结! 一、什…

[Ray Tracing in One Weekend] 笔记

前言 本文参照自raytracing in one weekend教程,地址为:https://raytracing.github.io/books/RayTracingInOneWeekend.html 什么是光线追踪? 光线追踪模拟现实中的成像原理,通过模拟一条条直线在场景内反射折射,最终…

Tinymce 5 插入代码集成highlight.js(踩坑记录)

目录 官方教程 坑点一 坑点二 坑点三 坑点四 TinyMCE HighLight.js Plugin 官方教程 1. 引入 tinymce 库文件 <script src"tinymce.min.js"></script> 2. 引入 highlight js 库文件 <script src"plugins/becodesample/highlight.js-11.…

word怎么分页?学会这几招,轻松掌握分页功能!

Microsoft Word作为办公文档处理的主力工具&#xff0c;其强大的排版功能为用户提供了丰富的文档编辑体验。其中&#xff0c;分页是一个常用但可能被忽视的重要功能&#xff0c;能够使文档结构更清晰、更易读。本文将向您介绍word怎么分页的三种方法&#xff0c;帮助您更好地掌…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Text文本组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之文本组件 一、操作环境 操作系统: Windows 10 专业版 IDE:DevEco Studio 3.1 SDK:HarmonyOS 3.1 二、文本组件 Text 是显示文本的基础组件之一&#xff0c;它可以包含子组件 Span &…

软件测试面试八股文(超详细整理)

请你说一说测试用例的边界 参考回答&#xff1a; 边界值分析法就是对输入或输出的边界值进行测试的一种黑盒测试方法。通常边界值分析法是作为对等价类划分法的补充&#xff0c;这种情况下&#xff0c;其测试用例来自等价类的边界。 常见的边界值 1)对16-bit 的整数而言 32…

ArkTS-一次开发,多端部署

展示 官方代码适配解读 官方代码&#xff1a;一次开发&#xff0c;多端部署-视频应用 解读 适配多端&#xff1a;根据屏幕大小来判断不同客户端&#xff0c;BreakpointSystem.ets中引入官方API获取 ohos.mediaqueryCommonConstants.ets定义好不同屏幕范围大小&#xff0c;供需…

反爬虫介绍及其处理方法

反爬虫机制 封IP&#xff1a;监控短时间内同一地址的请求次数过大登录及验证码&#xff1a;对于监控后封IP之后短时间内继续的大量请求&#xff0c;要求登陆或验证码通过验证之后才能继续进行。健全账号体制&#xff1a;即核心数据只能通过账号登录后才能进行访问。动态加载数…

Xpath注入

这里学习一下xpath注入 xpath其实是前端匹配树的内容 爬虫用的挺多的 XPATH注入学习 - 先知社区 查询简单xpath注入 index.php <?php if(file_exists(t3stt3st.xml)) { $xml simplexml_load_file(t3stt3st.xml); $user$_GET[user]; $query"user/username[name&q…

ubuntu 开机提示 you are in emergency mode,journalctl -xb

进入系统界面 回车输入&#xff1a; journalctl -xb -p3 查看出问题的盘符类型。 然后 lsblk 查看挂载情况 我的是/dev/sda3没有挂载上&#xff0c;对应/home目录&#xff0c;注意这时候不要直接mount 需要先修复 fsck -y /dev/sda3等待修复完成&#xff0c;在重新挂载 moun…

【网络安全技术】传输层安全——SSL/TLS

一、TLS位置及架构 TLS建立在传输层TCP/UDP之上&#xff0c;应用层之下。 所以这可以解决一个问题&#xff0c;那就是为什么抓不到HTTP和SMTP包&#xff0c;因为这两个在TLS之上&#xff0c;消息封上应用层的头&#xff0c;下到TLS层&#xff0c;TLS层对上层消息整个做了加密&…

Bert-vits2-v2.2新版本本地训练推理整合包(原神八重神子英文模型miko)

近日&#xff0c;Bert-vits2-v2.2如约更新&#xff0c;该新版本v2.2主要把Emotion 模型换用CLAP多模态模型&#xff0c;推理支持输入text prompt提示词和audio prompt提示语音来进行引导风格化合成&#xff0c;让推理音色更具情感特色&#xff0c;并且推出了新的预处理webuI&am…

GPT-4.5!!!

GPT-4 还没用明白&#xff0c;GPT-4.5 就要发布了。 最近&#xff0c;OpenAI 泄露了 GPT-4.5 的发布页面&#xff0c;除了进一步增强复杂推理和跨模态理解&#xff0c;GPT-4.5 增加了一个更加强大的功能——3D。 3D 功能的进一步支持&#xff0c;也就意味着多模态最后一块版图…

Linux部署Nacos注册中心结合内网穿透实现远程访问UI管理界面

文章目录 1. Docker 运行Nacos2. 本地访问Nacos3. Linux安装Cpolar4. 配置Nacos UI界面公网地址5. 远程访问 Nacos UI界面6. 固定Nacos UI界面公网地址7. 固定地址访问Plik8. 结语 Nacos是阿里开放的一款中间件,也是一款服务注册中心&#xff0c;它主要提供三种功能&#xff1a…

Keil的配置向导

配置向导 配置向导是一个集成的编辑器实用程序&#xff0c;用于在汇编、C/ c或初始化文件中生成类似gui的配置控件。使用源代码中的配置向导注释来生成控件。 官方例子 名称含义 Option 是设备属性&#xff0c;可以用树状结构表示。每个项目都可以有一个解释性的工具提示。V…

阿里云|人工智能(AI)技术解决方案

函数计算部署Stable Diffusion AI绘画技术解决方案 通过函数计算快速部署Stable Diffusion模型为用户提供快速通过文字生成图片的能力。该方案通过函数计算快速搭建了AIGC的能力&#xff0c;无需管理服务器等基础设施&#xff0c;专注模型的能力即可。该方案具有高效免运维、弹…

Ubuntu安装ARM交叉编译器

Ubuntu安装交叉编译器 更新apt # 更新apt sudo apt update安装gcc sudo apt install build-essential查看gcc版本 gcc -v下载交叉编译工具 复制到用户目录 解压 tar -xvf gcc-linaro-5.5.0-2017.10-x86_64_arm-linux-gnueabihf.tar.xz移动到/opt/下 sudo ./gcc-linaro-5.…