基於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 框架圖
補上一張框架圖,拖到瀏覽器新窗口,點擊放大便可清晰瀏覽,採用億圖製做,以便更好理解。