基于Redis消息的订阅发布应用场景
1.应用背景
在物联网采集管控系统中,先后端隔离的状况下,前端经过表单(好比按钮,开关,表格等)输入数据到数据库(好比MySql,经过WEBAPI服务端输入),而后采集控制端到数据库里去扫表取数据,将数据下发给物联网络中的终端设备(好比风扇控制板),从而来控制风扇的开跟关。前端
2.困境
采集控制端须要到数据库中去扫表。这个扫表操做会带来几个问题:git
2.1 锁表风险
扫表会有锁表风险,当该DBContext被占用的时候,其余线程不能实时使用此DBContext。github
2.2 实时性差
在物联网系统中,数据会很是多,好比有10000台设备,每台设备有100个采集控制点,则控制点最多可能会达到100W数据,这样去扫表,不只占用DBContext上下文的时间会很长,并且实时性会不好。web
2.3 增长编程复杂性
增长了采集服务端编程的复杂性。redis
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 实时效果好。api
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 框架图
补上一张框架图,拖到浏览器新窗口,点击放大便可清晰浏览,采用亿图制做,以便更好理解。