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 ...
随机推荐
- OA 框架
@{ Layout = null;}<!DOCTYPE html><html><head> <meta name="viewport&q ...
- WPF 中style文件的引用
原文:WPF 中style文件的引用 总结一下WPF中Style样式的引用方法: 一,内联样式: 直接设置控件的Height.Width.Foreground.HorizontalAlignment. ...
- php 二维数组相同值 相加
array(3) { [0]=> array(2) { ["sourcesid"]=> int(1) ["addusernum"]=> str ...
- 通过 vuex 实现 vue-echarts 图表的手动 resize
背景:项目有用到 vue-echarts, 百度推出的 vue 版本的 Echarts,图表自带响应式属性 auto-resize, 来实现窗口尺寸变化时,图表的尺寸自适应,但是发现它是靠监听 win ...
- ubuntu16.04安装搜狗输入法
安装完Ubuntu 16.04后,要更换为国内的软件源: Ali-OSM Alibaba Open Source Mirror Site Home About Join Us Ubuntu 1.软件包 ...
- Java FTP 基本操作
最近工作中用到了 FTP 相关的操作,所以借此机会了解了下具体内容. FTP基础 关于 FTP 基础推荐阅读<使用 Socket 通信实现 FTP 客户端程序>,其中需要特别注意的是主动模 ...
- Expression Blend学习二UI布局
什么是布局? · Panels控件(其实就是容器控件) · 对内部的子控件提供了自动布局功能 · 可以在容器控件内继续添加容器控件(一个复杂的界面往往是多种容器控件嵌套而组成的) · 一些界面器控件也 ...
- Android零基础入门第30节:两分钟掌握FrameLayout帧布局
原文:Android零基础入门第30节:两分钟掌握FrameLayout帧布局 前面学习了线性布局.相对布局.表格布局,那么本期来学习第四种布局--FrameLayout帧布局. 一.认识FrameL ...
- 核心思想:互联网创业十问?(大部分创业者是从学习借鉴成功者起步的,不需要把商业模式考虑完备,失败者没资格说趁着年轻...)4种失败的信号 good
著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:曹政链接:https://www.zhihu.com/question/20264499/answer/28168079来源: ...
- list 多行表头 表头合并
http://blog.csdn.net/safedebug/article/details/52971685