基于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客户端对象 csredisclient _redismq; //连接redis public csredisclient connectcsredis() { 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 实现层代码设计
// 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(); }
4.5 configureservices中依赖注入
在startup.cs中的configureservices方法进行依赖注入,如下。services.addscoped<iredismq, redismq>();
5.效果
5.1 打开风扇按钮
5.2 redisdesktopmanager工具中观察
在redisdesktopmanager的命令行窗口中输入psubscribe web,进行订阅web频道,如下
5.3 观察web频道输出信息
在前端控制了风扇打开操作之后如5.1,在redisdesktopmanager观察web频道输出信息
5.4 观察实际风扇效果
风扇实时打开。
上一篇: 一天一个Linux命令,第三天cat命令