zoukankan      html  css  js  c++  java
  • Redis发布与订阅

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

     举个例子:

    当右边窗口执行了后,

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

    Redis 的 SUBSCRIBE 命令可以让客户端订阅任意数量的频道, 每当有新信息发送到被订阅的频道时, 信息就会被发送给所有订阅指定频道的客户端。

    作为例子, 下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:

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

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

    1.1、订阅频道

    每个 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 字典, 程序只要检查某个频道是否为字典的键, 就可以知道该频道是否正在被客户端订阅; 只要取出某个键的值, 就可以得到所有订阅该频道的客户端的信息。

    订阅命令格式SUBSCRIBE channel [channel …],使用subscribe test就表示订阅来test这个频道。订阅后返回了三条信息。
    示例:

    1.2、退订频道

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

    若是想取消之前的订阅可以使用unsubscribe命令,格式为:UNSUBSCRIBE [channel [channel …]]
    如果没有频道被指定,也即是,一个无参数的 UNSUBSCRIBE 调用被执行,那么客户端使用 SUBSCRIBE 命令订阅的所有频道都会被退订。在这种情况下,命令会返回一个信息,告知客户端所有被退订的频道。
    示例:

    1.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)

    命令格式:PUBLISH channel message

    示例

    1.4、查看订阅消息

    PUBSUB 是一个查看订阅与发布系统状态的命令,格式:PUBSUB CHANNELS [pattern]。

    pattern 参数是可选的:

    • 如果不给出 pattern 参数,那么列出订阅与发布系统中的所有活跃频道。
    • 如果给出 pattern 参数,那么只列出和给定模式 pattern 相匹配的那些活跃频道。

    返回值
    一个由活跃频道组成的列表。

    PUBSUB 是一个查看订阅与发布系统状态的命令,格式:bashPUBSUB CHANNELS [pattern]

    示例:

    PubSub缺点
    PubSub的生产者传递过来一个消息,Redis会找到对应的消费者传递过去。如果一个消费者都没有,那么消息直接丢弃。
    如果有多个消费者,一个消费者突然断开连接,生产者会继续发送消息,其他正常连接的消费者可以持续收到消息。断开的消费者重新连接上,在断联期间生产者发送的消息,对这个消费者来说是彻底丢失了。
    如果Redis停机重启,PubSub的消息是不会持久化的,所有的消息都会被直接丢弃。因为这些缺点,消息队列领域几乎找不到合适的应用场景。

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

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

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

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

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

    2.1、订阅模式

    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 链表,程序可以检查所有正在被订阅的模式,以及订阅这些模式的客户端

    命令:PSUBSCRIBE pattern [pattern …] 订阅一个或多个符合给定模式的频道

    示例:

    2.2、退订模式

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

    命令:如果想取消之前的按模式订阅,可以使用PUNSUBSCRIBE [pattern [pattern …]]来取消

    示例:

    2.3、发送信息到模式

    发送信息到模式的工作也是由 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 频道匹配。

     

    https://redisbook.readthedocs.io/en/latest/feature/pubsub.html

    https://blog.csdn.net/qq_38030795/article/details/108580509

  • 相关阅读:
    怎么在虚拟机下的Linux系统安装数据库
    bbs仿博客
    算法思想
    vue前后台交互
    vue项目内文件的使用和配置
    pycharm使用vue
    vue之vue-cookies
    跨域请求
    vue的常用插件
    vue的生命周期
  • 原文地址:https://www.cnblogs.com/duanxz/p/14747968.html
Copyright © 2011-2022 走看看