发布订阅简介

除了使用List实现简单的消息队列功能以外,Redis还提供了发布订阅的消息机制。在这种机制下,消息发布者向指定频道(channel)发布消息,消息订阅者可以收到指定频道的消息,同一个频道可以有多个消息订阅者,如下图:

Redis也提供了一些命令支持这个机制,接下来我们详细介绍一下这些命令。

欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

发布订阅相关命令

在Redis中,发布订阅相关命令有:

  1. 发布消息
  2. 订阅频道
  3. 取消订阅
  4. 按照模式订阅
  5. 按照模式取消订阅
  6. 查询订阅信息

发布消息

发布消息的命令是publish,语法是:

publish 频道名称 消息

比如,要向channel:one-more-study:demo频道发布一条消息“I am One More Study.”,命令如下:

> publish channel:one-more-study:demo "I am One More Study."
(integer) 0

返回的结果是订阅者的个数,上例中没有订阅者,所以返回结果为0。

订阅消息

订阅消息的命令是subscribe,订阅者可以订阅一个或者多个频道,语法是:

subscribe 频道名称 [频道名称 ...]

比如,订阅一个channel:one-more-study:demo频道,命令如下:

> subscribe channel:one-more-study:demo
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel:one-more-study:demo"
3) (integer) 1

返回结果中有3条,分别表示:返回值的类型(订阅成功)、订阅的频道名称、目前已订阅的频道数量。当订阅者接受到消息时,就会显示:

1) "message"
2) "channel:one-more-study:demo"
3) "I am One More Study."

同样也是3条结果,分别表示:返回值的类型(信息)、消息来源的频道名称、消息内容。

新开启的订阅者,是无法收到该频道之前的历史消息的,因为Redis没有对发布的消息做持久化。

取消订阅

取消订阅的命令是unsubscribe,可以取消一个或者多个频道的订阅,语法是:

unsubscribe [频道名称 [频道名称 ...]]

比如,取消订阅channel:one-more-study:demo频道,命令如下:

> unsubscribe channel:one-more-study:demo
1) "unsubscribe"
2) "channel:one-more-study:demo"
3) (integer) 0

返回结果中有3条,分别表示:返回值的类型(取消订阅成功)、取消订阅的频道名称、目前已订阅的频道数量。

欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

按模式订阅消息

按模式订阅消息的命令是psubscribe,订阅一个或多个符合给定模式的频道,语法是:

psubscribe 模式 [模式 ...]

每个模式以 * 作为匹配符,比如 channel* 匹配所有以 channel 开头的频道,命令如下:

> psubscribe channel:*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "channel*"
3) (integer) 1

返回结果中有3条,分别表示:返回值的类型(按模式订阅成功)、订阅的模式、目前已订阅的模式数量。当订阅者接受到消息时,就会显示:

1) "pmessage"
2) "channel*"
3) "channel:one-more-study:demo"
4) "I am One More Study."

返回结果中有4条,分别表示:返回值的类型(信息)、消息匹配的模式、消息来源的频道名称、消息内容。

按模式取消订阅

按模式取消订阅的命令是punsubscribe,可以取消一个或者多个模式的订阅,语法是:

punsubscribe [模式 [模式 ...]]

每个模式以 * 作为匹配符,比如 channel:* 匹配所有以 channel 开头的频道,命令如下:

1> punsubscribe channel:*
1) "punsubscribe"
2) "channel:*"
3) (integer) 0

返回结果中有3条,分别表示:返回值的类型(按模式取消订阅成功)、取消订阅的模式、目前已订阅的模式数量。

欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

查询订阅信息

查看活跃频道

活跃频道指的是至少有一个订阅者的频道,语法是:

pubsub channels [模式]

比如:

> pubsub channels
1) "channel:one-more-study:test"
2) "channel:one-more-study:demo"
3) "channel:demo"
> pubsub channels *demo
1) "channel:one-more-study:demo"
2) "channel:demo"
> pubsub channels *one-more-study*
1) "channel:one-more-study:test"
2) "channel:one-more-study:demo"
查看频道订阅数
pubsub numsub [频道名称 ...]

比如:

> pubsub numsub channel:one-more-study:demo
1) "channel:one-more-study:demo"
2) (integer) 1
查看模式订阅数
> pubsub numpat
(integer) 1

代码实战

光说不练假把式,我们使用Java语言写一个简单的发布订阅示例。

Jedis集群示例

Jedis是Redis官方推荐的Java连接开发工具,我们使用Jedis写一个简单的集群示例。

package onemore.study;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig; import java.util.HashSet;
import java.util.Set; /**
* Jedis集群
*
* @author 万猫学社
*/
public enum Cluster {
INSTANCE; //为了简单,把IP和端口直接写在这里,实际开发中写在配置文件会更好。
private final String hostAndPorts = "192.168.0.60:6379;192.168.0.61:6379;192.168.0.62:6379";
private JedisCluster jedisCluster; Cluster() {
JedisPoolConfig poolConfig = new JedisPoolConfig(); //最大连接数
poolConfig.setMaxTotal(20);
//最大空闲数
poolConfig.setMaxIdle(10);
//最小空闲数
poolConfig.setMinIdle(2); //从jedis连接池获取连接时,校验并返回可用的连接
poolConfig.setTestOnBorrow(true);
//把连接放回jedis连接池时,校验并返回可用的连接
poolConfig.setTestOnReturn(true); Set<HostAndPort> nodes = new HashSet<>();
String[] hosts = hostAndPorts.split(";");
for (String hostport : hosts) {
String[] ipport = hostport.split(":");
String ip = ipport[0];
int port = Integer.parseInt(ipport[1]);
nodes.add(new HostAndPort(ip, port));
}
jedisCluster = new JedisCluster(nodes, 1000, poolConfig);
} public JedisCluster getJedisCluster() {
return jedisCluster;
}
}

欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

发布者示例

package onemore.study;

import redis.clients.jedis.JedisCluster;

/**
* 发布者
*
* @author 万猫学社
*/
public class Publisher implements Runnable {
private final String CHANNEL_NAME = "channel:one-more-study:demo";
private final String QUIT_COMMAND = "quit"; @Override
public void run() {
JedisCluster jedisCluster = Cluster.INSTANCE.getJedisCluster();
for (int i = 1; i <= 3; i++) {
String message = "第" + i + "消息";
System.out.println(Thread.currentThread().getName() + " 发布:" + message);
jedisCluster.publish(CHANNEL_NAME, message);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("------------------");
}
jedisCluster.publish(CHANNEL_NAME, QUIT_COMMAND);
}
}

订阅者示例

package onemore.study;

import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPubSub; /**
* 订阅者
*
* @author 万猫学社
*/
public class Subscriber implements Runnable {
private final String CHANNEL_NAME = "channel:one-more-study:demo";
private final String QUIT_COMMAND = "quit"; private final JedisPubSub jedisPubSub = new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
System.out.println(Thread.currentThread().getName() + " 接收:" + message);
if (QUIT_COMMAND.equals(message)) {
unsubscribe(CHANNEL_NAME);
}
}
}; @Override
public void run() {
JedisCluster jedisCluster = Cluster.INSTANCE.getJedisCluster();
jedisCluster.subscribe(jedisPubSub, CHANNEL_NAME);
}
}

欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

综合示例

package onemore.study;

public class App {
public static void main(String[] args) throws InterruptedException {
//创建3个订阅者
new Thread(new Subscriber()).start();
new Thread(new Subscriber()).start();
new Thread(new Subscriber()).start();
Thread.sleep(1000); //创建发布者
new Thread(new Publisher()).start();
}
}

运行结果如下:

Thread-6 发布:第1消息
Thread-0 接收:第1消息
Thread-1 接收:第1消息
Thread-2 接收:第1消息
------------------
Thread-6 发布:第2消息
Thread-0 接收:第2消息
Thread-1 接收:第2消息
Thread-2 接收:第2消息
------------------
Thread-6 发布:第3消息
Thread-0 接收:第3消息
Thread-2 接收:第3消息
Thread-1 接收:第3消息
------------------
Thread-0 接收:quit
Thread-1 接收:quit
Thread-2 接收:quit

微信公众号:万猫学社

微信扫描二维码

获得更多Java技术干货

最通俗易懂的Redis发布订阅及代码实战的更多相关文章

  1. redis发布订阅Java代码实现

    Redis除了可以用作缓存数据外,另一个重要用途是它实现了发布订阅(pub/sub)消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息. 为了实现redis的发布订阅机制,首先要打开re ...

  2. 我在生产项目里是如何使用Redis发布订阅的?(二)Java版代码实现(含源码)

    上篇文章讲了在实际项目里的哪些业务场景用到Redis发布订阅,这篇文章就讲一下,在Java中如何实现的. 图解代码结构 发布订阅的理论以及使用场景大家都已经有了大致了解了,但是怎么用代码实现发布订阅呢 ...

  3. RedisRepository封装—Redis发布订阅以及StackExchange.Redis中的使用

    本文版权归博客园和作者本人吴双共同所有,转载请注明本Redis系列分享地址.http://www.cnblogs.com/tdws/tag/NoSql/ Redis Pub/Sub模式 基本介绍 Re ...

  4. Redis发布订阅机制

    1. 什么是Redis Redis是一个开源的内存数据库,它以键值对的形式存储数据.由于数据存储在内存中,因此Redis的速度很快,但是每次重启Redis服务时,其中的数据也会丢失,因此,Redis也 ...

  5. Linux(6)- redis发布订阅/持久化/主从复制/redis-sentinel/redis-cluster、nginx入门

    一.redis发布订阅 Redis 通过 PUBLISH .SUBSCRIBE 等命令实现了订阅与发布模式. 其实从Pub/Sub的机制来看,它更像是一个广播系统,多个Subscriber可以订阅多个 ...

  6. 使用EventBus + Redis发布订阅模式提升业务执行性能

    前言 最近一直奔波于面试,面了几家公司的研发.有让我受益颇多的面试经验,也有让我感觉浪费时间的面试经历~因为疫情原因,最近宅在家里也没事,就想着使用Redis配合事件总线去实现下具体的业务. 需求 一 ...

  7. Redis 发布订阅,小功能大用处,真没那么废材!

    今天小黑哥来跟大家介绍一下 Redis 发布/订阅功能. 也许有的小伙伴对这个功能比较陌生,不太清楚这个功能是干什么的,没关系小黑哥先来举个例子. 假设我们有这么一个业务场景,在网站下单支付以后,需要 ...

  8. redis发布订阅客户端报错

    转自简书[https://www.jianshu.com/p/a85ec38245da] 最近遇到一个问题,springBoot程序中有一个监听器,监听redis中发来的消息(其实是监听一个key的消 ...

  9. Python 操作 Redis 发布订阅

    Python 操作 Redis 发布订阅 介绍 Redis可以通过多个客户机订阅相同的频道,一个服务机在相应频道进行发布,从而实现在客户机收听服务机发布相应信息,可以利用这个机制实现多个客户机之间的信 ...

随机推荐

  1. Web Scraping(网页抓取)基本原理 - 白话篇

    本文主要介绍 Web Scraping 的基本原理,基于Python语言,大白话,面向可爱的小白(^-^). 易混淆的名称: 很多时候,大家会把,在网上获取Data的代码,统称为"爬虫&qu ...

  2. coding++ :Layui-监听事件

    在使用layui的form表单做验证提交的时候,如果结合vue,或者是三级联动的时候,就需要做事件监听了. 具体语法: form.on('event(过滤器值)', callback); 可以用于监听 ...

  3. Django ORM查询结果是model对象

    xxx.object.get/filter()要查询出的结果为model对象,并不是需要的数据,如果使用需要model_to_dict()函数.

  4. jQuery数组去重复

    例如: var yearArray = new Array("三二一", "三二一", "学历", "学历", &quo ...

  5. 【WPF学习】第六十二章 构建更复杂的模板

    在控件模板和为其提供支持的代码之间又一个隐含约定.如果使用自定义控件模板替代控件的标准模板,就需要确保新模板能够满足控件的实现代码的所有需要. 在简单控件中,这个过程比较容易,因为对模板几乎没有(或完 ...

  6. 【python系统学习13】类(class)与对象(object)

    目录: 类(class)和实例 类 实例 小测试 对象(object) 属性和方法 类的创建 伪代码 示例代码 属性(attribute) 方法(method) 类的实例化 实例对象调用类属性和方法 ...

  7. D 楼房重建

    时间限制 : - MS   空间限制 : - KB  评测说明 : 1s,256m 问题描述 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊 ...

  8. ThinkPHP6.0学习笔记-模型操作

    ThinkPHP模型 模型定义 在app目录下创建Model目录,即可创建模型文件 定义一个和数据库表相匹配的模型 use think\Model; class User extends Model ...

  9. 浅谈头文件(.h)和源文件(.cpp)的区别

    浅谈头文件(.h)和源文件(.cpp)的区别 本人原来在大一写C的时候,都是所有代码写在一个文件里一锅乱煮.经过自己开始写程序之后,发现一个工程只有一定是由多个不同功能.分门别类展开的文件构成的.一锅 ...

  10. Go gRPC教程-客户端流式RPC(四)

    前言 上一篇介绍了服务端流式RPC,客户端发送请求到服务器,拿到一个流去读取返回的消息序列. 客户端读取返回的流的数据.本篇将介绍客户端流式RPC. 客户端流式RPC:与服务端流式RPC相反,客户端不 ...