RocketMQ 之 IoT 消息解析:物聯網需要什麼樣的消息技術?

作者:林清山(隆基)

前言:

從初代開源消息隊列崛起,到 PC 互聯網、移動互聯網爆發式發展,再到如今 IoT、雲計算、雲原生引領了新的技術趨勢,消息中間件的發展已經走過了 30 多個年頭。

目前,消息中間件在國內許多行業的關鍵應用中扮演着至關重要的角色。隨着數字化轉型的深入,客戶在使用消息技術的過程中往往同時涉及交叉場景,比如同時進行物聯網消息、微服務消息的處理,同時進行應用集成、數據集成、實時分析等,企業需要爲此維護多套消息系統,付出更多的資源成本和學習成本。

在這樣的背景下,2022 年,RocketMQ 5.0 正式發佈,相對於 RocketMQ 4.0,架構走向雲原生化,並且覆蓋了更多的業務場景。

物聯網消息場景

我們先來了解一下物聯網的場景是什麼?消息在物聯網裏面有什麼作用?

物聯網肯定是最近幾年最火的技術趨勢之一,有大量的研究機構、行業報告都提出了物聯網快速發展的態勢:

首先,物聯網設備規模爆發式增長,預測會在 2025 年達到 200 多億臺。

其次,物聯網的數據規模快速增長,來自物聯網的數據增速接近 28%,並且未來有 90% 以上的實時數據來自物聯網場景。這也就意味着未來的實時流數據處理的數據類型會有大量物聯網數據。

最後,邊緣計算是一個重要的趨勢,未來會有 75% 的數據在傳統數據中心或者雲環境之外來處理,這裏的邊緣指的是商店、工廠、火車等等這些離數據源更近的地方。由於物聯網產生的數據規模很大,如果全部數據傳輸到雲端處理,會面臨難以承受的成本,應該充分利用邊緣資源直接計算,再把高價值的計算結果傳輸雲端;另一方面,在離用戶近的地方計算直接響應,可以降低延遲,提升用戶體驗。

物聯網的發展速度這麼快,數據規模那麼大,跟消息有什麼關係呢?

我們通過這個圖來看一下消息在物聯網場景發揮的作用:

第一個作用是連接,承擔通信的職責,支持設備和設備的通信,設備和雲端應用的通信,比如傳感器數據上報、雲端指令下發等場景,作爲支撐 IoT 的應用架構,連接雲邊端。

第二個作用是數據處理,物聯網設備源源不斷的產生數據流,有大量需要實時流處理的場景,比如設備維護,高溫預警等等。基於 MQ 的事件流存儲和流計算能力,可以構建物聯網場景的數據架構。

物聯網消息技術

下面我們來看看在物聯網場景裏,對消息技術有什麼訴求?

我們先從這個表格來對比,物聯網消息技術跟之前講過的經典消息技術的區別。

經典的消息主要是爲服務端系統提供發佈訂閱的能力,而物聯網的消息技術是爲物聯網設備之間、設備和服務端之間提供發佈訂閱的能力。

我們來分別看一下各自場景的特點:

  • 經典消息場景

    消息 Broker、消息客戶端都作爲服務端系統的一部分,通常部署在 IDC 或者公共雲環境中配置性能較高的服務器上,包括容器、虛擬機、物理機等形式。消息客戶端和服務端通常部署在同一個機房,內網環境具有高帶寬和穩定的網絡質量。客戶端數量通常與應用服務器數量相對應,規模較小,一般是數百到數千臺服務器,只有超大型互聯網公司纔會達到百萬級。從消息生產的角度來看,每個客戶端的消息生產發送量一般對應到其業務的 TPS,能達到數百數千 TPS。在消息消費方面,通常採用集羣消費,一個應用集羣共享一個消費者 ID,共同分擔該消費組的消息。每條消息的訂閱比通常也不高,正常情況下不會超過 10 個。

  • IoT 消息場景

    很多條件都與經典消息場景不一樣,甚至截然相反。IoT 的消息客戶端通常是微型設備,其計算和存儲資源都非常有限。消息服務端可能要部署在邊緣環境中,使用的服務器配置也會比較低。另一方面,物聯網設備通常通過公網連接,網絡環境特別複雜,並且由於設備經常移動,有時會面臨斷網或處於弱網環境,網絡質量差且不穩定。物聯網場景中,消息客戶端實例數對應到物聯網設備數,可能達到億級別,遠遠超過大型互聯網公司的服務器數量。儘管每個設備的消息 TPS 不高,但是一條消息有可能同時被百萬個設備接收,訂閱比特別高。

RocketMQ - MQTT

由此可以看出,物聯網需要的消息技術和經典的消息技術很不一樣。接下來我們再來看,爲了應對物聯網的消息場景,RocketMQ 5.0 做了哪些事情?

RocketMQ 5.0 我們發佈了一個子產品,叫做 RocketMQ - MQTT。它有三個技術特點:

第一,它採用標準的物聯網協議 MQTT,該協議面向物聯網弱網環境、低算力的特點設計,協議十分精簡。它還提供豐富的特性,支持多種訂閱模式,多種消息 QoS,比如“最多一次”、“最少一次”和“當且僅當一次”。其領域模型設計也是基於“消息、主題、發佈訂閱”等概念,與 RocketMQ 高度兼容,爲構建一個雲端一體化的 RocketMQ 產品形態奠定了堅實的基礎。

第二,它採用存算分離的架構。RocketMQ Broker 作爲存儲層,MQTT 相關的領域邏輯都在 MQTT Proxy 層實現,並面向海量連接、訂閱關係、實時推送進行深度優化,Proxy 層可以根據物聯網業務負載提供獨立的彈性擴展,例如增加連接數只需新增 Proxy 節點。

第三,它採用端雲一體化的架構。因爲領域模型接近,並且以 RocketMQ 作爲存儲層,每條消息只需存儲一份,這份消息既能被物聯網設備消費,也能被雲端應用消費。另外,RocketMQ 本身是天然的流存儲,流計算引擎可以無縫對 IoT 數據進行實時分析。

接下來我們再從幾個關鍵的技術點,來深入瞭解 RocketMQ 的物聯網技術實現。

(一)IoT 消息存儲模型

1. 讀放大爲主,寫放大爲輔

首先要解決的是物聯網消息的存儲模型,在發佈訂閱的業務模型裏,一般會採用兩種存儲模型,一種是讀放大,每條消息只寫到一個公共隊列,所有消費者讀取這個共享隊列,維護自己的消費位點;另外一種是寫放大,每個消費者有自己的隊列,每條消息都分發到目標消費者的隊列中,消費者只讀自己的隊列。

因爲在物聯網場景裏,一條消息可能會有百萬級的設備消費,所以,很顯然,選擇讀放大的模型能顯著降低存儲成本、提高性能。

但是,只選擇讀放大的模式沒法完全滿足要求,MQTT 協議有其特殊性,它的 Topic 是多級 Topic,且訂閱方式既有精準訂閱,也有通配符匹配訂閱。比如家居場景,我們定義一個多級主題,如“家/浴室/溫度”,有直接訂閱完整多級主題的“家/浴室/溫度”,也有采用通配符訂閱只關注“溫度”的,還有隻關注一級主題爲“家”的所有消息。

對於直接訂閱完整的多級主題消費者可以採用讀放大的方式直接讀取對應多級主題的公共隊列;而採用通配符訂閱的消費者無法反推消息的 Topic,所以需要在消息存儲時根據通配符的訂閱關係多寫一個通配符隊列,這樣消費者就可以根據其訂閱的通配符隊列讀取消息。

這就是 RocketMQ 採用的讀放大爲主,寫放大爲輔的存儲模型。

2. 端雲一體化存儲

基於前文的分析,我們設計了 RocketMQ 端雲一體化的存儲模型,見下圖。

消息可以來自各個接入場景(如服務端的 RMQ/AMQP,設備端的 MQTT),但只會寫一份存到 Commitlog 裏面,然後分發出多個需求場景的隊列索引,比如服務端場景(MQ/AMQP)可以按照一級 Topic 隊列進行傳統的服務端消費,設備端場景可以按照 MQTT 多級 Topic 以及通配符訂閱進行消費消息。這樣我們就可以基於同一套存儲引擎,同時支持服務端應用集成和 IoT 場景的消息收發,達到端雲一體化。

(二)隊列規模問題

我們都知道像 Kafka 這樣的消息隊列每個 Topic 是獨立文件,但是隨着 Topic 增多,消息文件數量也增多,順序寫就退化成了隨機寫,性能明顯下降。RocketMQ 在 Kafka 的基礎上進行了改進,使用了一個 Commitlog 文件來保存所有的消息內容,再使用 CQ 索引文件來表示每個 Topic 裏面的消息隊列,因爲 CQ 索引數據比較小,文件增多對 IO 影響要小很多,所以在隊列數量上可以達到十萬級。但是,這個終端設備隊列的場景下,十萬級的隊列數量還是太小了,我們希望進一步提升一個數量級,達到百萬級隊列數量,所以,我們引入了 Rocksdb 引擎來進行 CQ 索引分發。

面向 IoT 的百萬級隊列設計

Rocksdb 是一個廣泛使用的單機 KV 存儲引擎,有高性能的順序寫能力。因爲我們有了 Commitlog 已具備了消息順序流存儲,所以可以去掉 Rocksdb 引擎裏面的 WAL,基於 Rocksdb 來保存 CQ 索引。在分發的時候,我們使用了 Rocksdb 的 WriteBatch 原子特性,分發時把當前的 MaxPhyOffset 注入進去,因爲 Rocksdb 能夠保證原子存儲,後續可以根據這個 MaxPhyOffset 來做 Recover 的 checkpoint。最後,我們也提供了一個 Compaction 的自定義實現,來進行 PhyOffset 的確認,以清理已刪除的髒數據。

(三)IoT 消息推送模型

介紹了底層的隊列存儲模型後,我們再詳細描述一下上層的消息實時推送(匹配查找和可靠觸達)是怎麼做的?

在 RocketMQ 的經典消費模式裏,消費者是直接採用長輪詢的方式,從客戶端直接發起請求,精確讀取對應的 Topic 隊列。而在 MQTT 場景裏,因爲客戶端數量、訂閱關係數量規模巨大,無法採用原來的長輪詢模式,消費鏈路的實現更加複雜,所以,這裏採用的是推拉結合的模型。

下圖展示的是一個推拉模型,物聯網終端設備通過 MQTT 協議連到 Proxy 節點。消息從服務端(MQ/AMQP/MQTT)發送過來,存到 Topic 隊列後,會有一個 notify 邏輯模塊來實時感知這個新消息到達,然後會生成消息事件(就是消息的 Topic 名稱),把這個事件推送至 Proxy 節點,Proxy 節點根據它連上的終端設備訂閱情況進行內部匹配,找到哪些終端設備能匹配上,然後會觸發 pull 請求去存儲層讀取消息,再推送到終端設備。

一個重要問題,就是訂閱關係的匹配查找。一般有兩種方式:第一種,簡單的廣播事件;第二種,集中存儲在線訂閱關係(比如圖裏的 lookup 模塊),然後進行匹配查找,再精準推送。

事件廣播機制看起來有擴展性問題,但是其實性能並不差,因爲我們推送的數據很小,就是 Topic 名稱,而且相同 Topic 的消息事件可以攢批推送,RocketMQ 5.0 就是默認採用的這個方式。集中存儲在線訂閱關係,這個也是常見的一種做法,如保存到 RDS、Redis 等等,但要保證數據的實時一致性也是有難度的,而且要進行匹配查找對整個消息的實時鏈路 RT 開銷也會有一定的影響。下圖模型中可以看到,在 Proxy 節點還會引入一個 Cache 模塊,用來做消息隊列 Cache,避免在廣播場景下每個終端設備都向存儲層發起讀數據的情況。

總結

本文分三個部分深入探討了 RocketMQ 5.0 關於物聯網消息技術的應用與優化,第一部分概述一個典型的物聯網技術架構,並重點闡述消息隊列在此架構中的關鍵作用。第二部分,探討了物聯網場景對消息技術的特殊要求,並分析這些要求與服務端應用中的消息技術之間的差異。第三部分,深入介紹了 RocketMQ 5.0 的 MQTT 子產品,闡釋其如何有效應對物聯網領域的技術挑戰。旨在爲大家提供一個全面的視角,理解消息隊列在物聯網中的重要性及其解決方案。

我們將持續爲您帶來深度剖析 RocketMQ 5.0 的系列文章,歡迎點擊此處進入官網瞭解更多詳情,也歡迎填寫表單進行諮詢:https://survey.aliyun.com/apps/zhiliao/bzT3AfPaq

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章