RocketMQ 5.0 架構解析:如何基於雲原生架構支撐多元化場景

本文將從技術角度瞭解 RocketMQ 的雲原生架構,瞭解 RocketMQ 如何基於一套統一的架構支撐多元化的場景。

文章主要包含三部分內容。首先介紹 RocketMQ 5.0 的核心概念和架構概覽;然後從集羣角度出發,從宏觀視角學習 RocketMQ 的管控鏈路、數據鏈路、客戶端和服務端如何交互;最後介紹消息隊列最重要的模塊存儲系統,瞭解 RocketMQ 如何實現數據的存儲和數據的高可用,以及如何利用雲原生存儲進一步提升競爭力。

01 概覽

在介紹 RocketMQ 的架構之前,先從用戶視角來看下 RocketMQ 的關鍵概念以及領域模型。如下圖,這裏按照消息的流轉順序來介紹。

在 RocketMQ 中,消息生產者一般對應業務系統的上游應用,在某個業務動作觸發後發送消息到 Broker。Broker 是消息系統數據鏈路的核心,負責接收消息、存儲消息、維護消息狀態、消費者狀態。多個 broker 組成一個消息服務集羣,共同服務一個或多個 Topic。

生產者生產消息併發送到 Broker,消息是業務通信的載體,每個消息包含消息 ID、消息 Topic、消息體內容、消息屬性、消息業務 key 等。每條消息都屬於某個 Topic,表示同一個業務的語義。

在阿里內部,交易消息的 Topic 被稱爲 Trade,購物車消息稱爲 Cart,生產者應用會將消息發送到對應的 Topic 上。Topic 裏還有 MessageQueue,用於消息服務的負載均衡與數據存儲分片,每個 Topic 包含一個或多個 MessageQueue,分佈在不同的消息 Broker。

生產者發送消息,Broker 存儲消息,消費者負責消費消息。消費者一般對應業務系統的下游應用,同一個消費者應用集羣共用一個 Consumer Group。消費者會與某個 Topic 產生訂閱關係,訂閱關係是 Consumer Group+Topic +過濾表達式的三元組,符合訂閱關係的消息會被對應的消費者集羣消費。

接下來就從技術實現角度進一步深入瞭解 RocketMQ。

02 架構概覽

下圖是一張 RocketMQ 5.0 的架構圖,RocketMQ 5.0 的架構從上往下可分爲 SDK、NameServer、Proxy 與 Store 層。

SDK 層包括 RocketMQ 的 SDK,用戶基於 RocketMQ 自身的領域模型來使用 SDK。除了 RocketMQ 自身的 SDK 之外,還包括細分領域場景的業界標準 SDK,比如面向事件驅動的場景,RocketMQ 5.0 支持 CloudEvents 的 SDK;面向 IoT 的場景,RocketMQ 支持物聯網 MQTT 協議的 SDK;爲了方便更多傳統應用遷移到 RocketMQ,還支持了 AMQP 協議,未來也會開源到社區版本里。

Nameserver 承擔服務發現與負載均衡的職責。通過 NameServer,客戶端能獲取 Topic 的數據分片與服務地址,鏈接消息服務器進行消息收發。

消息服務包含計算層 Proxy 與存儲層 RocketMQ Store。RocketMQ 5.0 是存算分離的架構,這裏的存算分離強調的主要是模塊和職責的分離。Proxy 與 RocketMQ Store 面向不同的業務場景可以合併部署,也可以分開部署。

計算層 Proxy 主要承載消息的上層業務邏輯,尤其是面向多場景、多協議的支持,比如承載 CloudEvents、MQTT、AMQP 的領域模型的實現邏輯與協議轉換。面向不同的業務負載,還可將 Proxy 分離部署,獨立彈性,比如在物聯網場景,Proxy 層獨立部署可以面向海量物聯網設備連接數進行彈性伸縮,與存儲流量擴縮容解耦。

RocketMQ Store 層則負責核心的消息存儲,包括基於 Commitlog 的存儲引擎、多元索引、多副本技術與雲存儲集成擴展。消息系統的狀態全部下沉到 RocketMQ Store,其組件全部實現無狀態化。

03 服務發現

下面詳細看一下 RocketMQ 的服務發現,如下圖所示。RocketMQ 的服務發現的核心是 NameServer,下圖是 Proxy 與 Broker 合併部署的模式,也是 RocketMQ 最常見的模式。

每個 Broker 集羣會負責某些 Topic 的服務,每個 broker 都會將自身服務的 topic 信息註冊到 NameServer(下面簡稱 NS)集羣,與每個 NameServer 進行通信,並定時與 NS 通過心跳機制來維持租約。服務註冊的數據結構包含 topic 與 topic 分片。示例中 broker1 與 broker2 分別承載 topicA 的一個分片。在 NS 機器上會維護全局視圖,topicA 有兩個分片分別在 broker1 與 broker2。

RocketMQ SDK 在對 TopicA 進行正式的消息收發之前,會隨機訪問 NameServer 機器,從而獲取到 topicA 有哪些分片,每個數據的分片在哪個 broker 上,與 broker 建立好長連接,然後再進行消息的收發。

大部分項目的服務發現機制會通過 zookeeper 或 etcd 等強一致的分佈式協調組件來擔任註冊中心的角色,而 RocketMQ 有自己的特點,如果從 CAP 的角度來看,註冊中心採用 AP 模式,NameServer 節點無狀態,是 shared-nothing 的架構,有更高的可用性。

如下圖,RocketMQ 的存算分離可分可合,採用分離的部署模式,RocketMQ SDK 直接訪問無狀態的 Proxy 集羣。該模式可以應對更復雜的網絡環境,支持多網絡類型的訪問如公網訪問,實現更好的安全控制。

在整個服務發現機制中,NameServer、Proxy 都爲無狀態,可以隨時進行節點增減。有狀態節點 Broker 的增減基於 NS 的註冊機制,客戶端可以實時感知、動態發現。在縮容過程中,RocketMQ Broker 還可以進行服務發現的讀寫權限控制,對縮容的節點禁寫開讀,待未讀消息全消費後,再實現無損平滑下線。

04 負載均衡

通過上文的介紹瞭解了 SDK 是如何通過 NameServer 來發現 Topic 的分片信息 MessageQueue,以及 Broker 地址的,基於這些服務發現的元數據,下面再來詳細介紹下消息流量是如何在生產者、RocketMQ Broker 和消費者集羣進行負載均衡的。

生產鏈路的負載均衡如下圖如所示:生產者通過服務發現機制獲取到 Topic 的數據分片以及對應的 Broker 地址。服務發現機制是比較簡單,在默認情況下采用 RoundRobin 的方式輪詢發送到各個 Topic 隊列,保證 Broker 集羣的流量均衡。在順序消息的場景下會略有不同,基於消息的業務主鍵 Hash 到某個隊列發送,如果有熱點業務主鍵,Broker 集羣也可能出現熱點。除此之外,基於元數據還能根據業務需要擴展更多的負載均衡算法,比如同機房優先算法,可以降低多機房部署場景下的延遲,提升性能。

消費者的負載均衡:擁有兩種類型的負載均衡方式,包括隊列級負載均衡和消息粒度的負載均衡。

最經典的模式是隊列級負載均衡,消費者知道 Topic 的隊列總數和同一個 Consumer Group 下的實例數,可以按照統一的分配算法,類似於一致性 hash 的方式,使每個消費者實例綁定對應隊列,只消費綁定隊列的消息,每個隊列的消息也只會被消費者實例消費。該模式最大的缺點是負載不均衡,消費者實例要綁定隊列且有臨時狀態。如果有三個隊列,有兩個消費者實例,則必然有消費者需要消費 2/3 的數據,如果有 4 個消費者,則第四個消費者會空跑。因此,RocketMQ 5.0 引入了消息粒度的負載均衡機制,無需綁定隊列,消息在消費者集羣隨機分發,保障消費者集羣的負載均衡。更重要的是,該模式更加符合未來 Serverless 化的趨勢,Broker 的機器數、Topic 的隊列數與消費者實例數完全解耦,可以獨立擴縮容。

05 存儲系統

前面通過架構概覽和服務發現機制,已經對 RocketMQ 有比較全局性的瞭解,接下來將深入 RocketMQ 的存儲系統。存儲系統對 RocketMQ 的性能、成本、可用性有決定性作用。RocketMQ 的存儲核心由 commitlog、ConsumeQueue 與 index 文件組成。

消息存儲首先寫到 commitlog,刷盤並複製到 slave 節點完成持久化,commitlog 是 RocketMQ 存儲的 source of true,可以通過它構建完整的消息索引。

相比於 Kafka,RocketMQ 將所有 topic 的數據都寫到 commitlog 文件,最大化順序 IO,使得 RocketMQ 單機可支撐萬級的 topic。

寫完 commitlog 之後,RocketMQ 會異步分發出多個索引,首先是 ConsumeQueue 索引,與 MessageQueue 對應,基於索引可以實現消息的精準定位,可以按照 topic、隊列 ID 與位點定位到消息,消息回溯功能也是基於該能力實現的。

另外一個很重要的索引是哈希索引,它是消息可觀測的基礎。通過持久化的 hash 表來實現消息業務主鍵的查詢能力,消息軌跡主要基於該能力實現。

除了消息本身的存儲之外,broker 還承載了消息元數據的存儲以及 topic 的文件,包括 broker 會對哪些 topic 提供服務,還維護了每個 topic 的隊列數、讀寫權限、順序性等屬性,subscription、consumer offset 文件維護了 topic 的訂閱關係以及每個消費者的消費進度,abort、checkpoint 文件則用於完成重啓後的文件恢復,保障數據完整性。

06 Topic 高可用

前面站在單機的視角,從功能的層面學習 RocketMQ 的存儲引擎,包括 commitlog 和索引。現在重新跳出來再從集羣視角看 RocketMQ 的高可用。

RocketMQ 的高可用指當 RocketMQ 集羣出現 NameServer、Broker 局部不可用時,指定的 topic 依然可讀可寫。

RocketMQ 可以應對三類故障場景。

場景 1:某對 Broker 的單機不可用

比如,當 Broker2 主節點宕機,備節點可用,TopicA 依然可讀可寫,其中分片 1 可讀可寫,分片 2 可讀不可寫,TopicA 在分片 2 的未讀消息依然可以消費。總結來說,即只要 Broker 集羣裏任意一組 Broker 存活一個節點,則 Topic 的讀寫可用性不受影響。如果某組 Broker 主備全部宕機,則 Topic 新數據的讀寫也不受影響,未讀消息會延遲,待任意主備啓動才能繼續消費。

場景 2:NameServer 集羣部分不可用

由於 NameServer 是 shared-nothing 架構,每個節點都爲無狀態,並且爲 AP 模式,無需依賴多數派算法,因此只要有一臺 NameServer 存活,則整個服務發現機制都正常,Topic 的讀寫可用性不受影響。

場景 3:NameServer 全部不可用

由於 RocketMQ 的 SDK 對服務發現元數據有緩存,只要 SDK 不重啓,依然可以按照當下的 topic 元數據繼續進行消息收發。

07 MessageQueue 的高可用基礎概念

上一個小節中講到 Topic 的高可用原理,從它的實現中可以發現雖然 Topic 持續可讀可寫,但是 Topic 的讀寫隊列數發生變化。隊列數變化,會對某些數據集成的業務有影響,比如說異構數據庫 Binlog 同步,同一個記錄的變更 binlog 會寫入不同的隊列,重放 binlog 可能會出現亂序,導致髒數據。所以還需要對現有的高可用進一步增強,要保障在局部節點不可用時,不僅 Topic 可讀可寫,並且 Topic 的可讀寫隊列數量不變,指定的隊列也是可讀可寫的。

如下圖,NameServer 或 Broker 任意出現單點不可用,Topic A 依然保持 2 個隊列,每個隊列都具備讀寫能力。

5.0 HA 的特點

爲了解決上述的場景,RocketMQ 5.0 引入全新的高可用機制,核心概念如下:

  • DLedger Controller:基於 raft 協議的強一致元數據組件,執行選主命令,維護狀態機信息。
  • SynStateSet:維護處於同步狀態的副本組集合,集合裏的節點都有完整的數據,主節點宕機後,從集合中選擇新的主節點。
  • Replication:用於不同副本之間的數據複製、數據校驗、截斷對齊等事項。

下面是 5.0 HA 的架構全景圖,新的高可用架構具備多個優勢。

  • 在消息存儲引入了朝代與開始位點的數據,基於這兩個數據完成數據校驗、截斷對齊,在構建副本組的過程中簡化數據一致性邏輯。
  • 基於 DledgerController,無需引入 zk、etcd 等外部分佈式一致性系統,並且 DledgerController 還可與 NameServer 合併部署,簡化運維、節約機器資源。
  • RocketMQ 對 DledgerController 是弱依賴,即便 Dledger 整體不可用,也只會影響選主,不影響正常的消息收發流程。
  • 可定製,用戶可以根據業務對數據可靠性、性能、成本綜合選擇,比如副本數可以是 2、3、4,副本直接可以是同步複製或異步複製。如 2-2 模式表示 2 副本並且兩個副本的數據同步複製;2-3 模式表示 3 副本,只要有 2 個副本寫成功即認爲消息持久化成功。用戶還可以將其中的副本部署在異地機房,異步複製實現容災。如下圖:

08 雲原生存儲-對象存儲

上文講到的存儲系統都是 RMQ 面向本地文件系統的實現,在雲原生時代,將 RocketMQ 部署到雲環境可以進一步利用雲原生基礎設施,比如雲存儲來進一步增強 RocketMQ 的存儲能力。RocketMQ 5.0 提供了多級存儲的特性,是內核級的存儲擴展,面向對象存儲擴展了對應的 Commitlog、ConsumeQueue 與 IndexFile。且採用了插件化的設計,多級存儲可以有多種實現,在阿里雲上基於 OSS 對象服務實現,在 AWS 上則可以面向 S3 的接口來實現。

通過引入了雲原生的存儲,RocketMQ 釋放了很多紅利。

第一個是無限存儲能力,消息存儲空間不受本地磁盤空間的限制,原來是保存幾天,現在可以幾個月、甚至存一年。另外對象存儲也是業界成本最低的存儲系統,特別適合冷數據存儲。

第二個是 Topic 的 TTL,原來多個 Topic 的生命週期是和 Commitlog 綁定,統一的保留時間。現在每個 Topic 都會使用獨立的對象存儲 Commitlog 文件,可以有獨立的 TTL。

第三個是存儲系統進一步的存算分離,能把存儲吞吐量的彈性和存儲空間的彈性分離。

第四個是冷熱數據隔離,分離了冷熱數據的讀鏈路,能大幅度提升冷讀性能,不會影響在線業務。

09 總結

  • RocketMQ 整體架構:

  • RocketMQ 負載均衡:AP 優先、分合模式、橫向擴展、負載粒度;
  • RocketMQ 存儲設計:存儲引擎、高可用、雲存儲。

作者:隆基

點擊立即免費試用雲產品 開啓雲上實踐之旅!

原文鏈接

本文爲阿里雲原創內容,未經允許不得轉載

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