zoukankan      html  css  js  c++  java
  • redis 发布和订阅实现

    参考文献

    1. 15天玩转redis —— 第九篇 发布/订阅模式
    2. 《Redis设计与实现》

    命令简介

    在redis用户手册中,跟发布订阅相关的命令有如下的六个:

    PSUBSCRIBE
    PUBLISH
    PUBSUB
    PUNSUBSCRIBE
    SUBSCRIBE
    UNSUBSCRIBE
    

    接下来一一简述下这个6个命令的相关使用。

    subscribe

    命令参考链接:http://redisdoc.com/pub_sub/subscribe.html

    SUBSCRIBE channel [channel ...]
    
    订阅给定的一个或多个频道的信息。
    

    SUBSCRIBE命令可以订阅一个频道。当有任何一个客户端向这个频道推送消息的时候,订阅了这个频道的客户端都可以收到数据。

    Psubscribe

    命令参考链接:http://redisdoc.com/pub_sub/psubscribe.html

    如上所述,客户端可以订阅一个频道的消息,那么我是否可以订阅满足一定条件的频道的所有消息呢?redis提供了Psubscribe命令,这个命令可以订阅符合模式的频道的消息。每个模式以 * 作为匹配符,比如 it* 匹配所有以 it 开头的频道( it.news 、 it.blog 、 it.tweets 等等), news.* 匹配所有以 news. 开头的频道( news.it 、 news.global.today 等等),诸如此类。

    PSUBSCRIBE pattern [pattern ...]
    

    UNSUBSCRIBE

    命令参考链接:http://redisdoc.com/pub_sub/unsubscribe.html

    我订阅了一个频道,也有需求退订。UNSUBSCRIBE命令就提供了客户端退订一个渠道的功能。

    UNSUBSCRIBE [channel [channel ...]]
    

    PUNSUBSCRIBE

    命令参考链接:http://redisdoc.com/pub_sub/psubscribe.html

    同理,如果我通过某个模式订阅了频道,我今天有点小后悔想退订这个模式咋办?使用PUNSUBSCRIBE命令就可以达成这个功能。

    publish

    命令参考链接:http://redisdoc.com/pub_sub/publish.html

    publish命令可以向一个频道推送消息。如上面说到的,如果使用publish命令向一个频道推送消息,则所有订阅了这个频道的客户端都可以收到这个消息。

    PUBLISH channel message
    

    PUBSUB

    命令参考链接:http://redisdoc.com/pub_sub/pubsub.html

    上面都是关于订阅和退订相关的功能的简述。如果我是管理redis的一个DBA,需要查看当前有多少个活跃的频道(活跃频道指的是那些至少有一个订阅者的频道),每个频道有多少的订阅者,有多少模式订阅的相关信息怎么办呢?redis给我们提供了PUBSUB命令。

    PUBSUB <subcommand> [argument [argument ...]]
    
    1. PUBSUB CHANNELS [pattern]:列出当前的活跃频道。活跃频道指的是那些至少有一个订阅者的频道,订阅模式的客户端不计算在内。

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

    1. PUBSUB NUMSUB [channel-1 ... channel-N] : 返回给定频道的订阅者数量,订阅模式的客户端不计算在内。

    2. PUBSUB NUMPAT : 返回订阅模式的数量。注意,这个命令返回的不是订阅模式的客户端的数量,而是客户端订阅的所有模式的数量总和。

    实现

    前面的篇幅主要介绍了redis提供的发布和订阅功能,接下来将介绍下发布和订阅功能具体是怎么实现的。

    订阅/退订一个频道

    当你在Redis客户端键入SUBSCRIBE的时候,就会建立一个客户端与一个频道的订阅关系。那么Redis是通过怎样的形式来完成这个关联的呢?在Redis中,将所有的频道和客户端的订阅关系都保存在一个叫puhsub_channels的字典中。这个字典的key是是某个频道,而values则是一个链表,记录了所有订阅这个频道的客户端。

    image

    struct redisServer{
        dict * pubsub_channels;
    }
    

    因此当建立一个客户端和频道的订阅关系的时候,大体会经历如下的两步操作:

    1. 如果该频道已经存在于pubsub_channels中,则将客户端加到这个链表的后面。
    2. 如果这个频道不存在,则在字典中建立一个新的频道,然后将客户端添加到链表中。

    退订的操作则和订阅的操作相反:

    1. 根据退订的频道是哪个,将链表上对应的客户端删除。
    2. 如果删除了客户端之后,整个链表为空,则表示这个频道没有被订阅,因此这个频道也将被删除 。

    模式订阅和退订

    前面的部分说到了一般的订阅和退订,接下来将介绍Redis模式的订阅是如何实现的。在Redis中所有的模式的订阅的关系都保存在服务器的pubsub_patterns 属性中。这个属性是一个链表结构。

    struct redisServer{
        list * pubsub_patterns;
    }
    

    链表结构中每一个节点都包含了一个pubsub_pattern 结构。

    image

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

    当客户端执行模式的订阅命令的时候,服务器会执行以下的几个操作:

    1. 新建一个pubsubPattern,将结构的pattern设置为被订阅的模式,client设置为订阅这个模式的客户端。
    2. 然后将这个结构体挂到pubsub_patterns的尾部。

    退订的操作则刚好相反:

    1. 遍历pubsub_pattern,找到客户端退订的模式,将这个链表的节点删除

    发送消息给频道订阅者

    如前面的章节所述,频道的订阅是通过pubsub_channels结构实现的。那么当推送一个消息给频道的订阅者的时候,则需要执行如下的几个操作:

    1. 根据频道的名称在dict pubsub_channels中找到对应的频道
    2. 遍历这个频道上所有的订阅者名单,将信息挨个发送给订阅者

    发送消息给模式订阅者

    那么模式的订阅的消息发送是如何实现的呢?其实实现的原理就更简单了,Redis会遍历pubsub_patterns上所有的链表节点,找到匹配的模式,然后发送消息。

  • 相关阅读:
    基于朴素贝叶斯的内容推荐算法
    Android Message和obtainMessage的差别
    hevc 的相关文章的链接
    创建不被杀死的service
    TQ2440 学习笔记—— 2、Win7PC 与虚拟机Ubuntu互通 ping 的网络设置
    国防科大校赛I题: Prime Summation
    VC 中怎样改变窗体背景色
    小心使用IHttpHandler下的IsReusable属性
    hdu1702(ACboy needs your help again!) 在杭电又遇坑了
    deque C++实现
  • 原文地址:https://www.cnblogs.com/bush2582/p/9440672.html
Copyright © 2011-2022 走看看