redis 发布和订阅实现
参考文献
- 15天玩转redis —— 第九篇 发布/订阅模式
- 《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 ...]]
- PUBSUB CHANNELS [pattern]:列出当前的活跃频道。活跃频道指的是那些至少有一个订阅者的频道,订阅模式的客户端不计算在内。
pattern 参数是可选的:
如果不给出 pattern 参数,那么列出订阅与发布系统中的所有活跃频道。
如果给出 pattern 参数,那么只列出和给定模式 pattern 相匹配的那些活跃频道。
PUBSUB NUMSUB [channel-1 ... channel-N] : 返回给定频道的订阅者数量,订阅模式的客户端不计算在内。
PUBSUB NUMPAT : 返回订阅模式的数量。注意,这个命令返回的不是订阅模式的客户端的数量,而是客户端订阅的所有模式的数量总和。
实现
前面的篇幅主要介绍了redis提供的发布和订阅功能,接下来将介绍下发布和订阅功能具体是怎么实现的。
订阅/退订一个频道
当你在Redis客户端键入SUBSCRIBE的时候,就会建立一个客户端与一个频道的订阅关系。那么Redis是通过怎样的形式来完成这个关联的呢?在Redis中,将所有的频道和客户端的订阅关系都保存在一个叫puhsub_channels的字典中。这个字典的key是是某个频道,而values则是一个链表,记录了所有订阅这个频道的客户端。
struct redisServer{
dict * pubsub_channels;
}
因此当建立一个客户端和频道的订阅关系的时候,大体会经历如下的两步操作:
- 如果该频道已经存在于pubsub_channels中,则将客户端加到这个链表的后面。
- 如果这个频道不存在,则在字典中建立一个新的频道,然后将客户端添加到链表中。
退订的操作则和订阅的操作相反:
- 根据退订的频道是哪个,将链表上对应的客户端删除。
- 如果删除了客户端之后,整个链表为空,则表示这个频道没有被订阅,因此这个频道也将被删除 。
模式订阅和退订
前面的部分说到了一般的订阅和退订,接下来将介绍Redis模式的订阅是如何实现的。在Redis中所有的模式的订阅的关系都保存在服务器的pubsub_patterns 属性中。这个属性是一个链表结构。
struct redisServer{
list * pubsub_patterns;
}
链表结构中每一个节点都包含了一个pubsub_pattern 结构。
typedef struct pubsubPattern {
redisClient * client ;
robj * pattern;
}pubsubPattern;
当客户端执行模式的订阅命令的时候,服务器会执行以下的几个操作:
- 新建一个pubsubPattern,将结构的pattern设置为被订阅的模式,client设置为订阅这个模式的客户端。
- 然后将这个结构体挂到pubsub_patterns的尾部。
退订的操作则刚好相反:
- 遍历pubsub_pattern,找到客户端退订的模式,将这个链表的节点删除
发送消息给频道订阅者
如前面的章节所述,频道的订阅是通过pubsub_channels结构实现的。那么当推送一个消息给频道的订阅者的时候,则需要执行如下的几个操作:
- 根据频道的名称在dict pubsub_channels中找到对应的频道
- 遍历这个频道上所有的订阅者名单,将信息挨个发送给订阅者
发送消息给模式订阅者
那么模式的订阅的消息发送是如何实现的呢?其实实现的原理就更简单了,Redis会遍历pubsub_patterns上所有的链表节点,找到匹配的模式,然后发送消息。
redis 发布和订阅实现的更多相关文章
- 文成小盆友python-num12 Redis发布与订阅补充,python操作rabbitMQ
本篇主要内容: redis发布与订阅补充 python操作rabbitMQ 一,redis 发布与订阅补充 如下一个简单的监控模型,通过这个模式所有的收听者都能收听到一份数据. 用代码来实现一个red ...
- Redis - 发布和订阅
一.概述 1). 发布和订阅是一种消息通信模式. 2). 优点:使消息订阅者和消息发布者耦合度降低,类似设计模式中的观察者模式. 二.发布和订阅 订阅命令: // 订阅一个或多个频道 // 返回值:v ...
- redis发布与订阅
发布与订阅 除了实现任务队列外, Redis还提供了一组命令可以让开发者实现"发布/订阅"(publish/subscribe)模式. "发布/订阅"模式同样可 ...
- redis 发布与订阅原理分析
前言:用了redis也有一段时间了,但是发布与订阅的使用频率也不高,趁着这次空闲,深究下redis的发布与订阅模式. 一.订阅频道和信息发布 功能说明:Redis 的 SUBSCRIBE 命令可以让客 ...
- Redis——发布和订阅
发布与订阅(又称pub/sub),订阅者(listener)负责订阅频道(channel),发送者(publisher)负责向频道发送二进制字符串消息(binary string message).每 ...
- php swoft redis 发布和订阅
//订阅 public function subscribe() { /* @var \Swoft\Redis\Redis $redis */ $redis = App::getBean(\Swoft ...
- Redis 发布与订阅模式
subscribe 订阅 publish 发布 频道 发布内容
- Redis 发布与订阅 消息
基于Redis消息队列-实现短信服务化 1.Redis实现消息队列原理 常用的消息队列有RabbitMQ,ActiveMQ,个人觉得这种消息队列太大太重,本文介绍下基于Redis的轻量级消息队列服务. ...
- 03 Redis发布与订阅
以qq群的公告,单个发布者,多个收听者为例 发布/订阅 实验 发布订阅的命令 PUBLISH channel msg 将信息 message 发送到指定的频道 channel SUBSCRIBE ch ...
随机推荐
- jquery表单过滤器
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...
- 简单实用SQL脚本Part:查找SQL Server 自增ID值不连续记录
原文:简单实用SQL脚本Part:查找SQL Server 自增ID值不连续记录 在很多的时候,我们会在数据库的表中设置一个字段:ID,这个ID是一个IDENTITY,也就是说这是一个自增ID.当并发 ...
- ARTS 12.24 - 12.28
从陈皓博主的专栏里学到一个概念,争取可以坚持下去: 每周一个 Algorithm,Review 一篇英文文章,总结一个工作中的技术 Tip,以及 Share 一个传递价值观的东西! 一个 Algori ...
- VS2008 环境中完美搭建 Qt 4.7.4 静态编译的调试与发布(很不错,有六张插图说明,修改qmake.conf里的MD参数等)good
为什么要在VS2008中使用QT静态编译呢?很简单,因为VS2008编译器编译出来的文件比mingw编译的要几乎小一半. 好了现在我们来做些准备工作,VS2008自然要安装的,然后打上SP1的补丁.然 ...
- QtScript, QML, Quick1, Quick2, Declarative 之间的关系
QtScript是基于 ECMAScript 的脚本语言 在脚本中可以访问原有C++代码中的QObject类型及其子类的实例,连接信号和槽:也可以创建QObject类型及其子类的实例. 但是QtScr ...
- Delphi中用MessageBox()API函数做倒计时对话框(使用Hook安装CBTHookCallback,计时器更改文字,SetWindowText API真正修改文字,引用未知函数)good
API有隐藏的MessageBoxTimeOut函数可以做计时对话框,缺点是不能显示还剩下多少秒关闭. const IDTIMEDOUT = 32000; function MessageBoxTim ...
- Linux升级OpenSSL版本
安装nginx的时候,出现了这样的问题: nginx : Depends: libssl1.0.0 (>= 1.0.2~beta3) but 1.0.1f-1ubuntu2.11 is to b ...
- C语言实现常用排序算法——基数排序
#include<stdio.h> #include<math.h> #define SIZE 10 #define C_SIZE 20 /*行数稳定=10,切记!列数务必搞的 ...
- # 构建以及运行Springboot Docker镜像时的变量传递
Docker可以把我们的运行环境打包,然后我们只要run就可以了.大部分hello world都是这么写的.但都缺少了实际应用环节.以springboot为例,hello world的Dockerfi ...
- JVM检测&工具
前几篇篇文章介绍了介绍了JVM的参数设置并给出了一些生产环境的JVM参数配置参考方案.正如之前文章中提到的JVM参数的设置需要根据应用的特性来进行设置,每个参数的设置都需要对JVM进行长时间的监测,并 ...