当前位置: 首页 > news >正文

php 实现mqtt 订阅监听功能出错_Redis发布订阅原理以及java实现

d84b5ecc8bbfad2485f5dacc77bfc72d.png

一、Redis发布订阅原理

Redis的架构包括两个部分:Redis Client和Redis Server,即客户端和服务端。客户端负责向服务器端发送请求并接受来自服务器端的响应。服务器端负责处理客户端请求,例如:数据存储,获取数据,修改数据等。

Redis通常用作数据库,缓存以及消息系统。

发布订阅的框架

bc7f4837e8821948bfc2a1307e5c5d3f.png

其中Publisher和Subscriber为Redis Client,channel为Redis server,而且发布者和订阅者是一对多的关系。

1、发布原理:

客户端和服务端可以理解为都各自维护着一个channel列表。

(1)PUBLISH

当客户端向某个频道发送消息时,Redis首先在结构体redisServer中的pubsub_channels中找出键为该频道的结点,遍历该结点的值,找出所有的客户端,将消息发送给这些客户端。然后,遍历结构体Redis Client中的pubsub_patterns,找出包含该频道的模式的结点,将消息发送给订阅了该模式的客户端。

da0af4e39447d249e5123290ef8b9b62.png

(2)SUBSCRIBE

首先,在客户端结构体client中,有一个属性为pubsub_channels,该属性表明了该客户端订阅的所有频道,它是一个字典类型,通过哈希表实现,其中的每个元素都包含了一个键值对以及指向下一个元素的指针,每次订阅都要向其中插入一个结点,键表示订阅的频道,值为空。然后,在表示服务器端的结构体redisServer中,也有一个属性为pubsub_channels,但此处它表示的是该服务器端中的所有频道以及订阅了这个频道的客户端,它也是一个字典类型,插入结点时,键表示频道,值则是订阅了这个频道的所有客户端组成的链表。最后Redis通知客户端其订阅成功。

36f5c1c363cfaff4d777d3a1a3a4bbca.png

(3)PSUBSCRIBE

当客户端订阅某个模式时,Redis同样需要将该模式和该客户端绑定。首先,在结构体client中,有一个属性为pubsub_patterns,该属性表示该客户端订阅的所有模式,它是一个链表类型,每个结点包括了订阅的模式和指向下一个结点的指针,每次订阅某个模式时,都要向其中插入一个结点。然后,在结构体redisServer中,有一个属性也叫pubsub_patterns,它表示了该服务器端中的所有模式和订阅了这些模式的客户端,它也是一个链表类型,插入结点时,每个结点都要包含订阅的模式,以及订阅这个模式的客户端,和指向下一个结点的指针,个人理解为是一种模糊匹配

da0af4e39447d249e5123290ef8b9b62.png

(4)UNSUBSCRIBE(退订)

UNSUBSCRIBE命令可以退订指定的频道, 这个命令执行的是订阅的反操作: 它从 pubsub_channels 字典的给定频道(键)中, 删除关于当前客户端的信息, 这样被退订频道的信息就不会再发送给这个客户端。

二、REDIS发布订阅和监听REDIS队列的区别

使用jedis的subscribe和publish实现的发布订阅系统 PK 使用jedis的BRPOP和BLPOP实现的阻塞时消息队列

1、redis队列为阻塞队列,获取完一个信息后会主动退出,如果想一直获取信息则需要开启一个监听;而发布订阅中的订阅端是自动完成的监听。

2、redis队列中的数据取出后就消失了,无法满足多端口;而发布订阅可以将数据发布到多个channel。

3、redis队列的数据不取出就会一直在缓存中;而发布订阅中订阅获取的数据不处理就消失了。

三、ActiveMQ和REDIS发布订阅的比较

1、ActiveMQ支持多种消息协议,包括AMQP,MQTT,Stomp等(ActiveMQ支持的传输协议 - winner_0715 - 博客园

2、ActiveMQ提供持久化功能;Redis消息被发送,如果没有订阅者接收,那么消息就会丢失

3、ActiveMQ提供了消息传输保障,当客户端连接超时或事务回滚等情况发生时,消息会被重新发送给客户端;Redis没有提供消息传输保障

4、ActiveMQ所提供的功能远比Redis发布订阅要复杂,毕竟Redis不是专门做发布订阅的;如果系统能够通过mq实现,则没必要使用mq

四、REDIS在客户端的操作

PUBLISH 和 subscribe

a4170b95d798016b96b6613c03d533ef.png

publish 和 PSUBSCRIBE

be2d3cb87572a74eda042ce0bd39ef6b.png

五、JAVA的实现

MAVEN依赖

 <!-- redis.clients " jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.1.0</version>
        </dependency>

PUBLISH

public Long publish(){
    System.out.println("发布者 ");
    Long res = null;
    try {
        Jedis jr = new Jedis("127.0.0.1", 6379, 0);// redis服务地址和端口号
        // jr客户端配置监听两个channel
        new Thread(()->{
            try {
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            jr.publish("mychannel", "test");
        }).start();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return res;
}

SUBSCRIBE

实现下面抽象类即可

public abstract class SubscriberService extends JedisPubSub {
 
    public abstract String getChannel();
 
    public abstract boolean dealMessage(String message);
 
    public void onMessage(String channel, String message) {
        dealMessage(message);
    }
 
    @PostConstruct
    public void init(){
        System.out.println("订阅者 ");
        Jedis jr = null;
        try {
            jr = new Jedis("127.0.0.1", 6379, 0);// redis服务地址和端口号
            // jr客户端配置监听两个channel
            jr.subscribe(this, "mychannel");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jr != null) {
                jr.disconnect();
            }
        }
    }
}

实现例子:

public class SubScribeRedis extends SubscriberService {
    @Override
    public String getChannel() {
        return "mychannel";
    }
 
    @Override
    public boolean dealMessage(String message) {
        System.out.println("--------"+message);
        return false;
    }
}

若有问题,下方留言~

---------------------

版权声明:本文为CSDN博主「Theo9」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/Theo9/article/details/98869532

作者:轻易科技-轻易贷研发部 赵少超

相关文章:

  • 前端工程师需要学习ps 吗_前端人员一定要掌握的PS技巧
  • 节能证书在哪里查询_证书查询
  • python 检查域名是否可以访问_python检查URL是否能正常访问
  • vue列表渲染中key的作用_React / Vue 项目时为什么要在列表组件中写 key,其作用是什么?...
  • vuepress侧边栏配置_侧边栏(sidebar) - VuePress 中文文档
  • python编写性别比例_python实现爬虫统计学校BBS男女比例(一)
  • iphone原彩显示对眼睛好吗_iPhone x手机原彩显示烧屏怎么办呢
  • linux 启动nacos报错_Nacos部署中的一些常见问题汇总
  • 中科院aibench_CVPR2019人脸防伪检测挑战赛Top3论文代码及模型解析
  • flutter 页面加载动画_为页面切换加入动画效果
  • 可变悬挂与空气悬挂的区别_可调悬挂和空气悬挂有什么区别啊,求解释
  • base64图裁剪 php_php解析base64数据生成图片的方法
  • cahrt框架 ios_iOS使用Charts框架绘制柱形图
  • 关于python搞笑段子精选_你能讲一个让人瞬间爆笑的笑话吗?
  • php yield 个人小解_php 新特性之yield大数组处理优化
  • ----------
  • 【402天】跃迁之路——程序员高效学习方法论探索系列(实验阶段159-2018.03.14)...
  • Cookie 在前端中的实践
  • DataBase in Android
  • Git同步原始仓库到Fork仓库中
  • IIS 10 PHP CGI 设置 PHP_INI_SCAN_DIR
  • Java多线程(4):使用线程池执行定时任务
  • jQuery(一)
  • PHP那些事儿
  • Vue学习第二天
  • 给新手的新浪微博 SDK 集成教程【一】
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 前端存储 - localStorage
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 嵌入式文件系统
  • 如何抓住下一波零售风口?看RPA玩转零售自动化
  • 实现简单的正则表达式引擎
  • 通过几道题目学习二叉搜索树
  • 为视图添加丝滑的水波纹
  • 转载:[译] 内容加速黑科技趣谈
  • 字符串匹配基础上
  • media数据库操作,可以进行增删改查,实现回收站,隐私照片功能 SharedPreferences存储地址:
  • kubernetes资源对象--ingress
  • ​什么是bug?bug的源头在哪里?
  • (1)STL算法之遍历容器
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (DFS + 剪枝)【洛谷P1731】 [NOI1999] 生日蛋糕
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (八)光盘的挂载与解挂、挂载CentOS镜像、rpm安装软件详细学习笔记
  • (附源码)ssm基于微信小程序的疫苗管理系统 毕业设计 092354
  • (数位dp) 算法竞赛入门到进阶 书本题集
  • (转)nsfocus-绿盟科技笔试题目
  • (转)利用ant在Mac 下自动化打包签名Android程序
  • (总结)Linux下的暴力密码在线破解工具Hydra详解
  • ***linux下安装xampp,XAMPP目录结构(阿里云安装xampp)
  • ./include/caffe/util/cudnn.hpp: In function ‘const char* cudnnGetErrorString(cudnnStatus_t)’: ./incl
  • .locked1、locked勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .net framework 4.0中如何 输出 form 的name属性。
  • .net 获取url的方法
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化