Redis的发布与订阅,有点类似于消息队列,发送者往频道发送消息,频道的订阅者接收消息。

1. 发布与订阅示例

首先,在本机开启第1个Redis客户端,执行如下命令订阅blog.redis频道:

SUBSCRIBE "blog.redis"

然后,在本机开启第2个Redis客户端,执行相同的命令订阅blog.redis频道:

然后,开启第3个Redis客户端,执行如下命令往blog.redis频道发送消息:

PUBLISH blog.redis "redis-in-action-01"

查看客户端1和客户端2,分别看到如下信息:

3个客户端与频道的关系如下图所示:

可以通过INFO clients命令查看连接的客户端数:

2. 订阅/退订频道

2.1 订阅频道

Redis的SUBSCRIBE命令用来订阅频道,使用方式如下所示:

SUBSCRIBE "blog.redis"

如果是订阅多个频道,可以使用如下所示命令:

SUBSCRIBE "blog.redis" "blog.rocketmq"

Redis将所有频道的订阅关系保存在服务器状态的pubsub_channels字典里,字典的键是某个被订阅的频道,键对应的值是1个链表,链表里记录了所有订阅这个频道的客户端。

以上图为例,说明客户端1、客户端2正在订阅频道"blog.redis",客户端3、客户端4正在订阅频道“blog.rocketmq”。

如果此时有1个客户端5,执行了如下命令:

SUBSCRIBE "blog.rocketmq" "blog.java"

那么服务器状态保存的频道订阅关系将变为如下图所示:

2.2 退订频道

Redis的UNSUBSCRIBE命令用来退订频道,使用方式如下所示:

UNSUBSCRIBE "blog.redis"

如果是退订多个频道,可以使用如下所示命令:

UNSUBSCRIBE "blog.redis" "blog.rocketmq"

假设现在服务器状态保存的频道订阅关系如下图所示:

如果此时客户端5,执行了如下命令:

UNSUBSCRIBE "blog.rocketmq" "blog.java"

那么服务器状态保存的频道订阅关系将变为如下图所示:

3. 订阅/退订模式

3.1 示例

首先,启动1个Redis客户端,执行如下命令订阅模式“blog.r*”:

PSUBSCRIBE "blog.r*"

然后,启动另1个Redis客户端,执行PUBLISH命令往频道发送消息:

PUBLISH "blog.redis" "redis-in-action-01"

PUBLISH "blog.rocketmq" "rocketmq-in-action-01"

PUBLISH "blog.java" "java-in-action-01"

可以看到,第1次启动的客户端可以接收到前2条消息,因为频道"blog.redis"、"blog.rocketmq"匹配模式“blog.r*”:

但频道"blog.java"不匹配该模式,所以最后1次发送的消息,该客户端未接收到。

3.2 订阅模式

Redis的PSUBSCRIBE命令用来订阅模式,使用方式如下所示:

PSUBSCRIBE "blog.r*"

如果是订阅多个模式,可以使用如下所示命令:

PSUBSCRIBE "blog.r*" "blog.j?va" "blog.j[ae]va"

Redis将所有模式的订阅关系保存在服务器状态的pubsub_patterns属性里。

pubsub_patterns属性是1个链表,链表中的每个节点是1个pubsub_Pattern结构,这个结构的pattern属性记录被订阅的模式,client属性记录订阅模式的客户端。

以上图为例,说明客户端1正在订阅模式"blog.r*,客户端2正在订阅模式“blog.j?va”。

如果此时有1个客户端3,执行了如下命令:

PSUBSCRIBE "blog.j[ae]va"

那么服务器状态保存的模式订阅关系将变为如下图所示:

3.3 退订模式

Redis的PUNSUBSCRIBE命令用来退订模式,使用方式如下所示:

PUNSUBSCRIBE "blog.r*"

如果是退订多个模式,可以使用如下所示命令:

PUNSUBSCRIBE "blog.j?va" "blog.j[ae]va"

假设现在服务器状态保存的模式订阅关系如下图所示:

如果此时客户端3,执行了如下命令:

PUNSUBSCRIBE "blog.j[ae]va"

那么服务器状态保存的模式订阅关系将变为如下图所示:

4. 发送消息

如果,服务器状态保存的频道订阅关系如下图所示:

服务器状态保存的模式订阅关系如下图所示:

此时,如果1个Redis客户端执行了以下PUBLISH命令:

PUBLISH blog.redis "redis-in-action-01"

那么,服务器会执行以下2个动作:

  1. 将消息"redis-in-action-01"发送给频道“blog.redis”的所有订阅者
  2. 将消息"redis-in-action-01"发送给与频道“blog.redis”相匹配模式的订阅者

也就是说,消息"redis-in-action-01"不仅会发送给频道“blog.redis”的订阅者客户端1、客户端2,也会发送给与频道“blog.redis”相匹配的模式“blog.r*”的订阅者客户端5。

5. 查看订阅信息

可以使用Redis的PUBSUB命令来查看频道或者模式的相关信息。

5.1 查看被订阅的频道

如果想要查看被订阅的频道信息,可以使用命令PUBSUB CHANNELS [pattern],其中pattern参数是可选的:

  1. 如果不指定pattern参数,返回服务器当前被订阅的所有频道
  2. 如果指定pattern参数,返回服务器被订阅的频道中与pattern模式相匹配的频道

这个命令的实现原理是通过遍历服务器状态保存的pubsub_channels字典来实现的。

举个具体的例子,如果服务器状态保存的pubsub_channels字典如下所示:

那么执行命令PUBSUB CHANNELS的返回结果如下所示:

执行命令PUBSUB CHANNELS r*的返回结果如下所示:

5.2 查看频道的订阅者数量

如果想要查看频道的订阅者数量,可以使用命令PUBSUB NUMSUB [channel1 channel2 ... channeln]

这个命令的实现原理是通过遍历服务器状态保存的pubsub_channels字典来实现的,频道对应的订阅者链表的长度就是该频道的订阅者数量。

举个具体的例子,如果服务器状态保存的pubsub_channels字典如下所示:

那么执行命令PUBSUB NUMSUB blog.redis blog.rocketmq blog.java的返回结果如下所示:

5.3 查看被订阅模式的数量

如果想要查看被订阅模式的数量,可以使用命令PUBSUB NUMPAT

这个命令的实现原理是返回服务器状态保存的pubsub_patterns链表的长度。

举个具体的例子,如果服务器状态保存的pubsub_patterns链表如下所示:

那么执行命令PUBSUB NUMPAT的返回结果如下所示:

6. 总结

Redis的发布与订阅有点类似于消息队列的发布与订阅,主要包含以下7个命令:

  1. SUBSCRIBE
  2. UNSUBSCRIBE
  3. PSUBSCRIBE
  4. PUNSUBSCRIBE
  5. PUBSUB CHANNELS
  6. PUBSUB NUMSUB
  7. PUBSUB NUMPAT

这7个命令的核心都是基于存储在服务器状态的pubsub_channels字典和pubsub_patterns链表实现的。

7. 参考

黄健宏 《Redis设计与实现》

Redis系列(八):发布与订阅的更多相关文章

  1. Redis中的发布与订阅

    redis中实现发布与订阅相对于zookeeper非常简单.直接使用publish和subscribe就行. subscrible news; 订阅news这个channel publish news ...

  2. Redis的消息发布和订阅

    Redis的消息发布和订阅 Author:SimpleWu GitHub-redis 什么是消息发布和订阅? Redis 发布订阅(pub/sub)是一种进程间的消息通信模式: 发送者(pub)发送消 ...

  3. redis 笔记06 发布与订阅、事务、慢查询日志、监视器

    发布与订阅 1. 服务器状态在pubsub_channels字典保存了所有频道的订阅关系:SUBSCRIBE命令负责将客户端和被订阅的频道关联到这个字典里面,而UNSUBSCRIBE命令则负责 解除客 ...

  4. Redis消息之发布与订阅

    "发布/订阅"可以实现进程间的消息传递 发布的消息不会持久化,只能收到订阅后的消息,执行subscribe命令后客户端会进入"订阅"状态,处于此状态下的客户端不 ...

  5. redis 事务 及发布于订阅功能

    事务: Redis事务可以一次执行多个命令,事务具有以下特征: 1.隔离操作:事务中的所有命令都会序列化.按顺序地执行,不会被其他命令打扰. 2.原子操作:事务中的命令要么全部被执行,要么全部都不执行 ...

  6. .NetCore使用Redis,StackExchange.Redis队列,发布与订阅,分布式锁的简单使用

    环境:之前一直是使用serverStack.Redis的客服端,今天来使用一下StackExchange.Redis(个人感觉更加的人性化一些,也是免费的,性能也不会差太多),版本为StackExch ...

  7. Redis系列(三)—— 订阅/发布

    Redis 订阅/发布 参考:http://www.cnblogs.com/mushroom/p/4470006.html,http://www.tuicool.com/articles/ABry2a ...

  8. Redis系列八:redis主从复制和哨兵

    一.Redis主从复制 主从复制:主节点负责写数据,从节点负责读数据,主节点定期把数据同步到从节点保证数据的一致性 1. 主从复制的相关操作 a,配置主从复制方式一.新增redis6380.conf, ...

  9. redis 实现消息发布和订阅

    1,打开二个客户端机器 一个用于发布,一个用于接受 2,发布一个channel1 3,用另外一个客户端收听上面的客户端 4,当再次在发布的redis客户端 发布一个消息  其他所有订阅的客户端会自动收 ...

随机推荐

  1. Java实现 LeetCode 220 存在重复元素 III(三)

    220. 存在重复元素 III 给定一个整数数组,判断数组中是否有两个不同的索引 i 和 j,使得 nums [i] 和 nums [j] 的差的绝对值最大为 t,并且 i 和 j 之间的差的绝对值最 ...

  2. java实现购物券消费方案

    公司发了某商店的购物券1000元,限定只能购买店中的m种商品.每种商品的价格分别为m1,m2,-,要求程序列出所有的正好能消费完该购物券的不同购物方法. 程序输入: 第一行是一个整数m,代表可购买的商 ...

  3. Java实现格子取数问题

    1 问题描述 有n*n个格子,每个格子里有正数或者0,从最左上角往最右下角走,只能向下和向右走,一共走两次(即从左上角往右下角走两趟),把所有经过的格子里的数加起来,求总和的最大值.如果两次经过同一个 ...

  4. Java实现无向图的欧拉回路判断问题

    1 问题描述 Problem Description 欧拉回路是指不令笔离开纸面,可画过图中每条边仅一次,且可以回到起点的一条回路.现给定一个图,问是否存在欧拉回路? Input 测试输入包含若干测试 ...

  5. java实现第五届蓝桥杯圆周率

    圆周率 数学发展历史上,圆周率的计算曾有许多有趣甚至是传奇的故事.其中许多方法都涉及无穷级数. 图1.png中所示,就是一种用连分数的形式表示的圆周率求法. 下面的程序实现了该求解方法.实际上数列的收 ...

  6. 从windows到Mac的那些坑

    今年入职一家新公司 公司办公统一使用Mac pro,所有国产软件不允许使用,只允许装国外的.开源的软件,,,,(这对一个从来没用过Mac的人来说,可真是头疼了一阵子) 经过几天的摸索,作一个简单的小总 ...

  7. sublime配置C++编译环境

    配置C++编译命令 { "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$", "workin ...

  8. vue甘特图gantt

    vue做甘特图,先大致介绍下核心功能: (1)横轴.纵轴拖拽: (2)自定义监听点击事件(双击.右键等)(3)任务之间显示父子层级关系:(4)左侧列表信息,右侧时间轴表示任务:(5)每个任务可以订制样 ...

  9. 【javascript的那些事】等待加载完js后执行方法

    很多时候,你也许会碰到 使用的情景: js文件b.js还没有从服务器端加载到web端,而吧a.js中已经调用了b.js中的方法 实例: 这里是加载echart的时候碰到的具体实例 引入js " ...

  10. Accord.NET重启4.0 开发

    Accord.NET Framework是在AForge.NET基础上封装和进一步开发来的.功能也很强大,因为AForge.NET更注重与一些底层和广度,而Accord.NET Framework更注 ...