zoukankan      html  css  js  c++  java
  • 基于Redis消息的订阅发布应用场景

    基于Redis消息的订阅发布应用场景

    1.应用背景

    在物联网采集管控系统中,前后端隔离的情况下,前端通过表单(比如按钮,开关,表格等)输入数据到数据库(比如MySql,通过WEBAPI服务端输入),然后采集控制端到数据库里去扫表取数据,将数据下发给物联网络中的终端设备(比如风扇控制板),从而来控制风扇的开跟关。

    2.困境

    采集控制端需要到数据库中去扫表。这个扫表操作会带来几个问题:

    2.1 锁表风险

    扫表会有锁表风险,当该DBContext被占用的时候,其他线程不能实时使用此DBContext。

    2.2 实时性差

    在物联网系统中,数据会非常多,比如有10000台设备,每台设备有100个采集控制点,则控制点最多可能会达到100W数据,这样去扫表,不仅占用DBContext上下文的时间会很长,而且实时性会很差。

    2.3 增加编程复杂性

    增加了采集服务端编程的复杂性。

    2.4 实时效果

    用户体验效果较差:客户点了开关控制风扇打开,然后底端设备需要很长时间才能真正打开。

    3.解决方案

    使用消息订阅发布方法。RabbitMQ比较重,故这里选用Redis的订阅发布功能,而且很多情况下Redis已经被作为缓存在引用,详见如下。

    3.1 前端传值给服务端

    前端将实时控制值以Restful API形式通过IP地址端口号+路由(比如:192.168.2.106:5000/ControlConfig)将此值传递给服务端。

    3.2 服务端通过消息传给采集控制端

    这里通过nuget获得CSRedisCore,来操作Redis的订阅发布功能。采集控制端订阅消息。服务端发布消息。这样操作达到了如下目的:2.1不用经过数据库消息的实时传递;2.2 实时性好;2.3 编程也简单;2.4 实时效果好。

    4.详细代码设计

    4.1 CSRedisCore

    CSRedis 是 redis.io 官方推荐库,支持 redis-trib集群、哨兵、私有分区与连接池管理技术,简易 RedisHelper 静态类。
    https://www.nuget.org/packages/CSRedisCore/
    通过Nuget获得CSRedisCore库

    4.2 接口设计如下

    详细说明参考注释。

    using CSRedis;
    namespace IBMS.Infrastruct.Redis
    {
        public interface IRedisMQ
        {   //连接Redis
            CSRedisClient ConnectCSRedis();
            //订阅频道
            void SubscribeCSRedis(string ChannelName);
            //把message异步发布Redis的频道
            void PublishAsyncCSRedis(string channel, string message);
            //释放Redis
            void DisposeCSRedis();
            //订阅接受下来的msg的方法
            void Rcv(string Msg, string channel);
        }
    }
    

    4.3 接口实现如下

    详细说明见注释

    using System;
    using CSRedis;
    using IBMS.Infrastruct.Appsetting;
    
    namespace IBMS.Infrastruct.Redis
    {
        public class RedisMQ : IRedisMQ
        {
            //读取连接Redis字符串
            private readonly string connectRedis = Appsettings.app(new string[] { "AppSettings", "RedisCaching", "ConnectionString" });//按照层级的顺序,依次写出来     
            //定义一个Redis客户端对象
            static CSRedisClient _RedisMQ;
            //连接Redis
            public CSRedisClient ConnectCSRedis()
            {       
                //如果已经连接实例,直接返回
                if (_RedisMQ != null)
                {
                    return _RedisMQ;
                }    
               return _RedisMQ = new CSRedisClient(connectRedis);
            }
            //释放Redis
            public void DisposeCSRedis()
            {
                _RedisMQ.Dispose();
            }
           //异步发布消息到Redis的某个频道
            public void PublishAsyncCSRedis(string channelName, string message)
            {
                _RedisMQ.PublishAsync(channelName, message);
            }
    
            //如果自己需要用消息值,需要想方法返回数据
            //订阅消息的处理方法
            public void Rcv(string channel, string Msg)
            {
                Console.WriteLine($"{DateTime.Now.ToLongDateString()}|Rcv:{channel},Msg:{Msg}");
            }
            //订阅消息
            public void SubscribeCSRedis(string ChannelName)
            {     
                _RedisMQ.Subscribe((ChannelName, msg => Rcv(msg.Channel, msg.Body)));
            }
    
        }
    }
    

    4.4 ConfigureServices中依赖注入

    在Startup.cs中的ConfigureServices方法进行依赖注入,如下。
    services.AddScoped<IRedisMQ, RedisMQ>();

    4.5 创建一个RedisMQ的消息对象

    在Controller里定义创建一个消息对象,这一步的前提是需要依赖注入,依赖注入在某种意义上跟C语言的typedef有点像,将typedef会将控制权交给编译器,编译器定义新类型,然后程序运行之后就可以就可以随意通过新类型来定义对象。
    IRedisMQ _RedisMQ =new RedisMQ();

    4.6 实现层代码设计

            // PUT: api/ControlConfig/5
            [HttpPut]
            public async Task  Update([FromBody] ControlConfig ControlConfig)
            {
               _RedisMQ.ConnectCSRedis();
               _RedisMQ.SubscribeCSRedis("web");
               _RedisMQ.PublishAsyncCSRedis("web", $"add at{DateTime.Now}");
               _RedisMQ.PublishAsyncCSRedis("web", $"{SerializeHelper.Serialize(ControlConfig)}");
               Console.ReadKey();
               _RedisMQ.DisposeCSRedis();
            }
    

    5.效果

    5.1 打开风扇按钮

    5.2 RedisDesktopManager工具中观察

    在RedisDesktopManager的命令行窗口中输入PSUBSCRIBE web,进行订阅web频道,如下

    5.3 观察web频道输出信息

    在前端控制了风扇打开操作之后如5.1,在RedisDesktopManager观察web频道输出信息

    5.4 观察实际风扇效果

    风扇实时打开。
    备注:采集控制端跟设备端是基于TCP长连接组网方式,协议用的是基于MODBUS的变种,比如加入我们自己的包头包尾包类型等信息,这里不做展开

    6 框架图

    补上一张框架图,拖到浏览器新窗口,点击放大即可清晰浏览,采用亿图制作,以便更好理解。

    7 GitHub

    Demo地址:
    https://github.com/JerryMouseLi/RedisMQDemo.git

  • 相关阅读:
    Java显示指定类型的文件
    Mysql B-Tree, B+Tree, B*树介绍
    java海量大文件数据处理方式
    RandomAccessFile读取文本简介
    ConcurrentHashMap1.7和1.8的不同实现
    Java并发中的CopyOnWrite容器
    Java阻塞队列的实现
    JVM之Java虚拟机详解
    Spring AOP的实现原理
    SpringMVC工作原理
  • 原文地址:https://www.cnblogs.com/JerryMouseLi/p/11012839.html
Copyright © 2011-2022 走看看