客戶有一堆小裝置,需要通過小程式來控制它們,主要是裝置門的開關、電源開關、狀態查詢、壓力控制等。下面主要紀錄下設計思路。原始碼地址:https://gitee.com/bxjg1987/abp
最初的設計是這樣的
核心流程有3個,分別用綠、藍、黑這3種顏色來標識。
流程1:小程式端傳送指令控制裝置(開關、艙壓調整等)
以開關電源控制為例
- 小程式向wei服務端發起請求,說我想關閉裝置id為1的那個裝置
- wei服務端準備一條訊息(說我要關閉id為1的那個裝置),傳送給RabbitMQ訊息佇列
- RabbitMQ訊息佇列將訊息推送給硬體伺服器
- 硬體伺服器解析訊息,根據裝置id和按協議約定準備byte[]指令下發給具體裝置
- 裝置回覆訊息給硬體伺服器
- 硬體伺服器組織一條回覆訊息(所id為1的裝置已經關閉成功)傳送給RabbitMQ訊息佇列
- 訊息佇列將回復訊息推送給web服務端
- web服務端通過abp提供的通知功能(預設基於a's'p.net core signalr)通知小程式端,
此時小程式端開源認為操作成功,但是不是太準確,另一種辦法是小程式再查一次裝置狀態確認下。所以上面的步驟5可以向裝置觸發一個請求,讓裝置立即上報一次資料。預設情況下裝置是輪詢的比如30秒上報一次資料。
流程2:裝置輪詢30秒上報一次資料
- 裝置上報狀態資料
- 硬體伺服器將裝置狀態資料儲存到資料庫
- 硬體伺服器向RabbitMQ訊息佇列傳送一條訊息,說裝置id為x的裝置上報了狀態資料
- RabbitMQ訊息佇列將訊息推送給web服務端
- web服務端通過abp提供的通知機制通知小程式端
步驟3沒必要直接將狀態資料推送給訊息佇列,因為此訊息的接收方未必關係具體的資料,目前設計只是說有裝置狀態上報了,這個訊息通知到接收方,由接收方決定是否主動來查裝置狀態
流程3:小程式主動查詢裝置狀態
這個就比較簡單了
- 小程式端向web服務端發起查詢請求
- web伺服器直接從資料庫查詢裝置狀態返回就可以了
有點問題,這樣查詢不是裝置的當前狀態,我們可以再定義介面直接去查一次當前裝置的狀態,但是這樣編碼比較大,也不利於我們複用現有流程。最簡單的辦法是定義一個介面,向裝置傳送一條指令說請你立即上報一次資料,小程式原有的查詢裝置狀態查到就是最新的了。
裝置服務端SuperSocket
開源地址:https://github.com/kerryjiang/SuperSocket,這是個設計得比較好的,基於.net core的socket的通訊框架。官方有文件學起來比較簡單。
它負責與裝置通訊,可以單獨部署在一臺伺服器上。
基於Abp的Web服務端
這就不多說了,因為它已經為我們提供了很好的web服務端基礎設施,免得從頭做起。此服務端也可以單獨部署一臺伺服器
訊息佇列RabbitMQ
其它mq沒用過,就用它咯。它主要是解耦裝置服務端和web服務端的,主要是它可以主動推送訊息給接收方,也可以考慮使用redis的推送來實現。訊息佇列也可以單獨部署一臺伺服器
簡化後的設計
如果裝置比較少,請求量不大可以用下面這種簡化的設計
既然是簡化,流程就不說了。主要是省略了訊息佇列,並且省略了指令回覆的處理,而是使用輪詢的方式,比如每過10秒查一次當前裝置狀態,控制裝置時,只是下發指令,而不等結果,因為我們的輪詢會查到下一次的裝置狀態。
這裡有些注意:
- 裝置上報狀態存入資料庫時可以使用一個全域性的資料庫連線
- web伺服器向裝置伺服器傳送指令時也可以考慮使用全域性的tcp連線
- web伺服器向裝置伺服器傳送指令時可以使用supersocket提供的客戶端庫
結束
簡化後的方案最low,但是也最容易實現,目前原始碼中就是採用的這種方式。前一種方式稍微好點,3臺伺服器可以分開部署,如果併發再大點可以考慮下分散式了,再不行就放棄這個上思路,直接上個阿里雲IOT啥的。