参考文献

  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则是一个链表,记录了所有订阅这个频道的客户端。

struct redisServer{
dict * pubsub_channels;
}

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

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

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

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

模式订阅和退订

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

struct redisServer{
list * pubsub_patterns;
}

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

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上所有的链表节点,找到匹配的模式,然后发送消息。

redis 发布和订阅实现的更多相关文章

  1. 文成小盆友python-num12 Redis发布与订阅补充,python操作rabbitMQ

    本篇主要内容: redis发布与订阅补充 python操作rabbitMQ 一,redis 发布与订阅补充 如下一个简单的监控模型,通过这个模式所有的收听者都能收听到一份数据. 用代码来实现一个red ...

  2. Redis - 发布和订阅

    一.概述 1). 发布和订阅是一种消息通信模式. 2). 优点:使消息订阅者和消息发布者耦合度降低,类似设计模式中的观察者模式. 二.发布和订阅 订阅命令: // 订阅一个或多个频道 // 返回值:v ...

  3. redis发布与订阅

    发布与订阅 除了实现任务队列外, Redis还提供了一组命令可以让开发者实现"发布/订阅"(publish/subscribe)模式. "发布/订阅"模式同样可 ...

  4. redis 发布与订阅原理分析

    前言:用了redis也有一段时间了,但是发布与订阅的使用频率也不高,趁着这次空闲,深究下redis的发布与订阅模式. 一.订阅频道和信息发布 功能说明:Redis 的 SUBSCRIBE 命令可以让客 ...

  5. Redis——发布和订阅

    发布与订阅(又称pub/sub),订阅者(listener)负责订阅频道(channel),发送者(publisher)负责向频道发送二进制字符串消息(binary string message).每 ...

  6. php swoft redis 发布和订阅

    //订阅 public function subscribe() { /* @var \Swoft\Redis\Redis $redis */ $redis = App::getBean(\Swoft ...

  7. Redis 发布与订阅模式

    subscribe  订阅 publish   发布   频道    发布内容

  8. Redis 发布与订阅 消息

    基于Redis消息队列-实现短信服务化 1.Redis实现消息队列原理 常用的消息队列有RabbitMQ,ActiveMQ,个人觉得这种消息队列太大太重,本文介绍下基于Redis的轻量级消息队列服务. ...

  9. 03 Redis发布与订阅

    以qq群的公告,单个发布者,多个收听者为例 发布/订阅 实验 发布订阅的命令 PUBLISH channel msg 将信息 message 发送到指定的频道 channel SUBSCRIBE ch ...

随机推荐

  1. Debug权限提升

    procedure SetPrivilege; var OldTokenPrivileges, TokenPrivileges: TTokenPrivileges; ReturnLength: dwo ...

  2. 手把手教你学会 基于JWT的单点登录

      最近我们组要给负责的一个管理系统 A 集成另外一个系统 B,为了让用户使用更加便捷,避免多个系统重复登录,希望能够达到这样的效果--用户只需登录一次就能够在这两个系统中进行操作.很明显这就是单点登 ...

  3. git 专题

    $ git pull origin test // git pull合并代码的时候,若发生冲突,会处于merging状态,检查代码,发现自己的分支低于主分支,这个时候想撤销merge // 撤销mer ...

  4. Win8 Metro(C#)数字图像处理--2.48Canny边缘检测算法

    原文:Win8 Metro(C#)数字图像处理--2.48Canny边缘检测算法  [算法说明] Canny边缘检测算法可以分为4步:高斯滤波器平滑处理.梯度计算.非极大值抑制.双阈值边缘检 测和 ...

  5. 向github提交本地项目

    首先你需要一个github账号,所有还没有的话先去注册吧! https://github.com/ 我们使用git需要先安装git工具,这里给出下载地址,下载后一路直接安装即可: https://gi ...

  6. xgboost参数及调参

    常规参数General Parameters booster[default=gbtree]:选择基分类器,可以是:gbtree,gblinear或者dart.gbtree和draf基于树模型,而gb ...

  7. 青云QingCloud宣布完成C轮融资,金额1亿美元

    本轮融资由两家人民币基金领投,蓝驰创投跟投. 企业级基础云服务商青云QingCloud正式宣布完成金额为1亿美元的C轮融资,本轮融资由两家人民币基金领投,蓝驰创投跟投. 青云QingCloud公司成立 ...

  8. IntelliJ IDEA热部署

    如何对webAPP实施热部署:     首先修改Configurations里面的       其次在设置中修改     使用debug模式运行即可

  9. 配置QSslConfiguration让客户端程序跳过本地SSL验证

    大家下午好哦.今天我们在重新制作我们萌梦聊天室的时候,出现了这样的问题.那就是我们的客户端能够对qtdream.com服务器进行登录,但是不能对localhost服务器(也就是本机啦)进行登录.这究竟 ...

  10. Dependency Injection 筆記 (2)

    续上集,接着要说明如何运用 DI 来让刚才的范例程序具备执行时期切换实现类型的能力. (本文摘自電子書<.NET 依賴注入>) 入门范例—DI 版本 为了让 AuthenticationS ...