基於訊息佇列 RocketMQ 的大型分散式應用上雲最佳實踐

阿里巴巴雲原生發表於2021-11-04

作者|紹舒
稽核&校對:歲月、佳佳
編輯&排版:雯燕

前言

訊息佇列是分散式網際網路架構的重要基礎設施,在以下場景都有著重要的應用:

  • 應用解耦
  • 削峰填谷
  • 非同步通知
  • 分散式事務
  • 大資料處理

並涉及互動直播、移動網際網路&物聯網,IM 實時通訊、Cache 同步、日誌監控等多個領域。

而本文主要圍繞著商業版本的訊息佇列 RocketMQ,和開源版本 RocketMQ 進行比較,並結合一些實踐中的場景來展示大型分散式應用的上雲最佳實踐。

1.png

核心能力

商業版本訊息佇列 RocketMQ 相比較開源版本 RocketMQ 和其他競品,主要有以下幾點優勢。

  1. 開箱即用、功能豐富
  2. 高效能、無限擴充套件能力
  3. 可觀測、免運維能力
  4. 高 SLA 和穩定性保證

2.png

開箱即用、功能豐富

訊息佇列 RocketMQ 提供了定時、事務、順序等多型別訊息的支援,且支援廣播、叢集兩種消費模式;另外在協議層面,提供 TCP/HTTP 多協議支援,還提供了 TAG/SQL 屬性過濾功能,極大程度地拓寬了使用者的使用場景。

高效能、無限擴充能力

訊息佇列 RocketMQ 經受了阿里核心電商曆年雙十一洪峰的考驗,支援千萬級 TPS 訊息收發和億級訊息堆積的能力,並且能夠為訊息提供毫秒級端到端延遲保障,另外還提供分級儲存,支援海量訊息的任意儲存時間。

可觀測、免運維能力

訊息佇列 RocketMQ 提供了一個可觀測性大盤,支援細粒度資料大盤,提供了訊息全鏈路生命週期追蹤和查詢能力,對各個指標提供了相應的監控報警功能;此外,還提供了訊息回溯和死信佇列功能,能夠保證使用者的訊息能夠隨時回溯消費。

高 SLA 和穩定性保障

訊息佇列 RocketMQ 的穩定性是我們一貫、持續、穩定投入的重要領域,提供了高可用部署和多副本寫入功能;另外也支援同城多 AZ 容災和異地多活。

產品剖面

接下來,我們會從以上的產品核心能力中挑選幾個剖面,並且結合具體的場景和實踐來做進一步的介紹。

多訊息型別支援

高可用順序訊息

商業版本訊息佇列 RocketMQ 使用的順序訊息我們稱之為高可用順序訊息。在介紹高可用順序訊息之前,首先簡要介紹下開源版本 RocketMQ 的順序訊息。

順序訊息分為兩種型別,全域性順序訊息和分割槽順序訊息。

  • 全域性順序訊息:在 RocketMQ 儲存層只會分配一個分割槽,也就是說全域性順序 Topic 的可用性跟單一副本的可用性強相關,且不具備可擴充套件的能力。
  • 分割槽順序訊息:所有訊息根據 Sharding Key 進行分割槽。同一個分割槽內的訊息按照嚴格的 FIFO 順序進行釋出和消費。Sharding Key 是順序訊息中用來區分不同分割槽的關鍵欄位。

下圖是分割槽順序訊息的應用場景,order ID 即為此時順序訊息的 Sharding Key。

3.png

可以看到,無論是全域性順序訊息還是分割槽順序訊息,都依賴了單一分割槽天然的 FIFO 特性來保證順序,因此順序性也只能在同一個分割槽內保證,當此分割槽所在的副本不可用時,順序訊息並不具備重試到其他副本的能力,此時訊息的順序性就難以得到保證。

為了解決這一問題,我們設計並實現了高可用順序訊息。

高可用順序訊息有以下幾個特點:

  • 一個邏輯順序分割槽(PartitionGroup)下有多個物理分割槽。
  • 其中任意一個物理分割槽是可寫的,那麼整個邏輯分割槽是可寫且有序的。
  • 我們基於 happened-before 的原則設計了一套基於分割槽位點的排序演算法。
  • 根據該演算法,消費者在消費某一邏輯分割槽時,會從其所屬的各個物理分割槽中拉取訊息並進行合併排序,得出正確的訊息順序流。

4.png

通過這樣的設計,高可用順序訊息解決了下列幾點問題:

  • 可用性問題:高可用順序訊息將具備與普通訊息一致的可用性,在某副本不可用時,可快速重試至其它副本。
  • 可擴充套件性問題:普通順序訊息,特別是普通全域性順序訊息,不具備良好的擴充套件能力,只能固定在特定的副本中。高可用順序訊息的邏輯順序分割槽可以將物理順序分割槽分散在多個副本中。
  • 熱點問題:普通順序訊息根據 Key 將一類訊息 Hash 至同一個分割槽中,熱點 Key 會導致熱點分割槽,高可用順序訊息具備橫向擴充套件能力,可以為邏輯順序分割槽新增多個物理分割槽來消除熱點問題。
  • 單點問題:普通全域性順序訊息,僅包含單分割槽,極易出現單點故障,高可用順序訊息可以消除全域性順序訊息的單點問題。

尤其需要注意的是熱點問題,在阿里巴巴內部某電商業務大促時,因傳送到順序 Topic 的某一特定的 ShardingKey 數量過多,叢集中一個副本接收到了大量該 ShardingKey 的訊息,導致該副本超出其負荷上限,造成了訊息的延遲和堆積,一定程度上影響了業務。在使用了高可用順序訊息之後,由於其在多物理分割槽中的負載均衡特性,提升了叢集順序訊息的承載能力,從而避免了熱點問題的出現。

秒級精準定時訊息

定時訊息,是指客戶端當前傳送但希望在未來的某個時間內收到的訊息。定時訊息廣泛應用於各類排程系統或者業務系統之中。比如支付訂單,產生一個支付訊息,系統通常需要在一定時間後處理該訊息,判斷使用者是否支付成功,然後系統做相應處理。

開源版本的 RocketMQ 只支援幾個指定的延遲級別,並不支援秒級精度的定時訊息。而面向集團內和雲上多樣化的需求,開源版本的定時訊息並不能滿足我們的需求,因此我們推出了秒級精準定時訊息。

5.png

如下圖所示,我們基於時間輪設計並實現了支援任意定時時間的秒級精準定時訊息,同時滿足以下特性:

  • 任意定時時間
  • 超長定時時間
  • 海量定時訊息
  • 刪除定時訊息
  • 高可用
  • 高效能

6.png

內部某使用者有這樣的場景,期望在未來的某一分鐘的 30s 時刻處理這樣一個定時請求,開源版本的定時訊息並不符合其需要,而秒級精準定時訊息在保證高可用、高效能的同時,滿足了其業務需求。

分散式事務訊息

如下圖所示,在傳統的事務處理中,多個系統之間的互動耦合到一個事務中,造成整體的相應時間長,回滾過程複雜,從而潛在影響了系統的可用性;而 RocketMQ 提供的分散式事務功能,在保證了系統鬆耦合和資料最終一致性的前提下,實現了分散式事務。

7.png

訊息佇列 RocketMQ 提供的事務訊息處理步驟如下:

  • 傳送方將半事務訊息傳送至訊息佇列 RocketMQ 版服務端。
  • 訊息佇列 RocketMQ 版服務端將訊息持久化成功之後,向傳送方返回 Ack 確認訊息已經傳送成功,此時訊息為半事務訊息。
  • 傳送方開始執行本地事務邏輯。
  • 傳送方根據本地事務執行結果向服務端提交二次確認(Commit 或是 Rollback),服務端收到 Commit 狀態則將半事務訊息標記為可投遞,訂閱方最終將收到該訊息;服務端收到 Rollback 狀態則刪除半事務訊息,訂閱方將不會接受該訊息。

基於這樣的實現,我們通過訊息實現了分散式事務特性,即本地事務的執行結果會最終反應到訂閱方是否能接收到該條訊息。

8.png

訊息佇列 RocketMQ 的分散式事務訊息廣泛地應用於阿里巴巴核心交易鏈路中,通過分散式事務訊息,實現了最小事務單元;交易系統和訊息佇列之間,組成一個事務處理;下游系統(購物車、積分、其它)相互隔離,並行處理。

分級儲存

背景

隨著雲上客戶的不斷增多,儲存逐漸成為 RocketMQ 運維的重要瓶頸,這包括並且不限於:

  • 記憶體大小有限,服務端不能將所有使用者的資料全部快取在記憶體中;在多租戶場景下,當有使用者拉取冷資料時,會對磁碟造成較大 IO 壓力,從而影響共享叢集的其他使用者,亟需做到資料的冷熱分離。
  • 雲上有單租戶定製化訊息儲存時長的需求。而 RocketMQ Broker 中所有使用者的訊息是放在一個連續檔案中進行儲存的,無法針對任何單一使用者定製儲存時長,即現有的儲存結構無法滿足這樣的需求。
  • 如果能對海量資料提供更低成本的儲存方式,可以大幅降低雲上 RocketMQ 的磁碟儲存成本。

基於以上現狀,分級儲存方案應運而生。

架構

分級儲存的整體架構如下:

  1. connector 節點負責將 broker 上的訊息實時同步到 OSS 上
  2. historyNode 節點將使用者對冷資料的拉取請求轉發至 OSS 上
  3. 在 OSS 中是按照 Queue 粒度來組織檔案結構的,即每個 Queue 會由獨立的檔案進行儲存,從而保證了我們可以針對於租戶定義訊息的儲存時長。

9.png

通過這樣的設計,我們實現了訊息資料的冷熱分離。

10.png

使用場景

基於分級儲存,我們進一步擴充了使用者的使用場景:

  1. 自定義儲存時間:在訊息資料的冷熱分離之後,我們將冷資料儲存到 OSS 這樣的儲存系統中,能夠實現使用者自定義的儲存時間。
  2. 訊息審計:在訊息的儲存之間從數天擴充套件到自定義後,訊息的屬性從一個臨時性的中轉資料變成了使用者的資料資產,而訊息系統也從資料中樞轉變成了資料倉儲;使用者能夠基於資料倉儲實現更多樣的審計、分析、處理功能。
  3. 訊息回放:在流計算場景中,訊息回放是非常重要的一個場景;通過擴充訊息的儲存時間之後,流計算能夠實現更加豐富的計算分析場景。

穩定性

訊息佇列 RocketMQ 的穩定性是我們一貫、持續、穩定投入的重要領域。在介紹我們在穩定性的最新工作之前,首先帶大家回顧下 RocketMQ 高可用架構的演進路線。

高可用架構演進路線

2012 年,RocketMQ 作為阿里巴巴全新一代的訊息引擎問世,並隨後開源至社群,第一代 RocketMQ 高可用架構也隨之誕生。如下圖所示,第一代高可用架構採取當時流行的 Master-Slave 主從架構,寫流量經過 Master 節點同步至 Slave 節點,讀流量也經過 Master 節點並將消費記錄同步至 Slave 節點。當 Master 節點不可用時,整個副本組可讀不可寫。

11.png

2016 年,RocketMQ 雲產品正式開始商業化,雲時代單點故障頻發,雲產品需要完全面向失敗而設計,因此 RocketMQ 推出了第二代多副本架構,依託於 Zookeeper 的分散式鎖和通知機制,引入 Controller 元件負責 Broker 狀態的監控以及主備狀態機轉換,在主不可用時,備自動切換為主。第二代架構是訊息雲產品規模化程式中的核心高可用架構,為雲產品規模化立下了汗馬功勞。

2018 年,RocketMQ 社群對 Paxos 和 Raft 引入分散式協議有極大的熱情,RocketMQ 研發團隊在開源社群推出了基於 Raft 協議的 Dledger 儲存引擎,原生支援 Raft 多副本。

RocketMQ 高可用架構已經走過了三代,在集團、公有云和專有云多樣場景的實踐中,我們發現這三套高可用架構都存在一些弊端:

  • 第一代主備架構只起到了冷備的作用,且主備切換需要人工介入,在大規模場景下有較大的資源浪費以及運維成本。
  • 第二代架構引入了 Zookeeper 和 Controller 節點,架構上更加複雜,在主備切換做到了自動化,但故障轉移時間較長,一般是 10 秒左右完成選主。
  • 第三代 Raft 架構目前暫未在雲上和阿里集團內大規模應用,且 Raft 協議就決定了需要選主,新主還需要被客戶端路由發現,整個故障轉移時間依然較長;另外,強一致的 Raft 版本並未支援靈活的降級策略,無法在可用性和可靠性之間做靈活的權衡。

為了應對雲上日益增長的業務規模、更嚴苛的 SLA 要求、複雜多變的專有云部署環境,當前的訊息系統需要一種架構簡單、運維簡單、有基於當前架構落地路徑的方案,我們將其稱作秒級 RTO 多副本架構。

新一代秒級 RTO 多副本架構

秒級 RTO 多副本架構是訊息中介軟體團隊設計實現的新一代高可用架構,包含副本組成機制、Failover 機制、對現有元件的侵入性修改等。

整個副本組有以下特點:

  • Strong Leader/No Election:Leader 在部署時確定,整個生命週期內不會發生切換,但可在故障時被替換。
  • 僅 Leader 支援訊息寫入:每一個副本組僅 Leader 接受訊息寫入,Leader 不可用時,整個副本組不可寫入。
  • 所有的副本支援訊息讀取:雖然 Leader 上擁有全量的訊息,Follower 上的訊息量不對等,但所有的副本都支援訊息的讀取。
  • 靈活的副本組數量:可以基於可靠性、可用性和成本自由選擇副本組的數量。
  • 靈活的 Quorum 數量:最終所有的訊息都會同步到整個副本組上,但副本組內可以靈活配置寫成功最小副本數。例如 2-3 模式,3 副本情況下,2 副本成功即為寫成功。同時,在副本不可用的情況下,Quorum 數量也可以動態自行降級。

在上述副本組的概念下,故障轉移可以複用當前 RocketMQ 客戶端的機制來完成。如下圖所示:

12.png

  1. Producer 在主不可用時,靈活快速地切換至另一個副本組。
  2. Consumer 在某個副本不可用時可快速切換至同副本組另一個副本上進行訊息消費。

可觀測性

健康大盤

我們在可觀測性方面也做了大量的工作,為使用者提供了一個訊息系統的可觀測性健康資料大盤。如下圖所示,使用者能夠清晰的看到例項級別、topic 級別、group 級別的各種監控資料,能夠全方面地監控、診斷問題。

13.png

訊息鏈路追蹤

另外我們還基於訊息軌跡提供了訊息全鏈路軌跡追蹤功能。如下圖所示,使用者能夠在控制檯上看到完整的訊息生命週期、從訊息的傳送、儲存、到消費,整個鏈路都能被完整地記錄下來。

14.png

應用場景

客戶痛點:業務出現消費堆積的使用者需要根據訊息軌跡抽樣資料,綜合分析後才能大致判斷引起問題原因,排查困難。

核心價值:提高線上執行問題排查的效率,和問題定位的準確性。直接在健康大盤上快速發現風險最高的 Topic 和 Group,並根據各個指標的變化情況快速定位原因。例如訊息處理時間過長可以擴容消費者機器或優化消費業務邏輯,如果是失敗率過高可以快速檢視日誌排除錯誤原因。

事件驅動

大家一定非常熟悉 Gartner,在2018年的一個評估報告裡,Gartner 將 Event-Driven Model,列為了未來10大戰略技術趨勢之一,並且,做出了兩個預測:

  • 2022年,超過 60% 的新型數字化商業解決方案,都會採用事件通知的軟體模型。
  • 2022年,超過 50% 的商業組織,將會參與到EDA生態系統當中去。

同一年,CNCF 基金會也提出了 CloudEvents,意在規範不同雲服務之間的事件通訊協議標準。到目前為止,CloudEvents也已經發布了多個訊息中介軟體的繫結規範。

可見事件驅動是未來業務系統的一個重要趨勢,而訊息天然具備和事件的親近性,因此訊息佇列 RocketMQ,是堅決擁抱事件驅動的。

談到訊息和事件,這裡做一個簡單的闡述:訊息和事件是兩種不同形態的抽象,也意味著滿足不同的場景:

  • 訊息:訊息是比事件更通用的抽象,常用於微服務呼叫之間的非同步解耦,微服務呼叫之間往往需要等到服務能力不對等時才會去通過訊息對服務呼叫進行非同步化改造;訊息的內容往往繫結了較強的業務屬性,訊息的傳送方對訊息處理邏輯是有明確的預期的。
  • 事件:事件相對於訊息更加具像化,代表了事情的傳送、條件和狀態的變化;事件源來自不同的組織和環境,所以事件匯流排天然需要跨組織;事件源對事件將被如何響應沒有任何預期的,所以採用事件的應用架構是更徹底的解耦,採用事件的應用架構將更加具備可擴充套件性和靈活性。

在2020年,阿里雲釋出了事件匯流排 EventBridge 這一產品,其使命是作為雲事件的樞紐,以標準化的 CloudEvents 1.0 協議連線雲產品和雲應用,提供中心化的事件治理和驅動能力,幫助使用者輕鬆構建鬆耦合、分散式的事件驅動架構;另外,在阿里雲之外的雲市場上有海量垂直領域的 SaaS 服務,EventBridge 將以出色的跨產品、跨組織以及跨雲的整合與被整合能力,助力客戶打造一個完整的、事件驅動的、高效可控的上雲新介面。

而藉助事件匯流排 EventBridge 提供的事件源功能,我們能夠打通訊息到事件的鏈路,使得訊息佇列 RocketMQ 具備事件驅動的動力,從而擁抱整個事件生態。接下來我們將藉助一個案例,如下圖所示,為大家展示這一功能。

15.png

建立訊息佇列 RocketMQ 主題

16.png

建立目標服務

我們基於容器服務快速建立一個事件驅動的服務,計算負載 Deployment 的 yaml 如下,該服務能夠響應事件並將結果列印到標準輸出中。

apiVersion: apps/v1 # for versions before 1.8.0 use apps/v1beta1
kind: Deployment
metadata:
  name: eventbridge-http-target-deployment
  labels:
    app: eventbridge-http-target
spec:
  replicas: 2
  selector:
    matchLabels:
      app: eventbridge-http-target
  template:
    metadata:
      labels:
        app: eventbridge-http-target
    spec:
      containers:
      - name: eb-http-target
        # 下述映象暴露了一個 HTTP 地址(/cloudevents)用於接收 CloudEvents,原始碼參考:https://github.com/aliyuneventbridge/simple-http-target
        image: registry.cn-hangzhou.aliyuncs.com/eventbridge-public/simple-http-target:latest
        ports:
        - containerPort: 8080

前往容器服務控制檯,進入服務與路由的服務頁面,建立一個私網訪問型別的 Service,並做好埠對映。

17.png

建立事件匯流排 EventBridge 自定義匯流排

我們來到事件匯流排 EventBridge 控制檯,建立一個自定義匯流排 demo-with-k8s。

18.png

建立事件匯流排 EventBridge 自定義匯流排規則

我們為匯流排 demo-with-k8s 建立一個規則,並選擇 HTTP 作為事件目標,選擇專有網路型別,選中對應的 VPC、 VSwitch 以及安全組,並指定目標URL,如下圖所示:

19.png

建立事件匯流排 EventBridge 事件源

我們為該自定義事件匯流排新增訊息佇列 RocketMQ 版的自定義事件源。

20.png

傳送 RocketMQ 訊息

接下來我們回到訊息佇列 RocketMQ 控制檯,通過控制檯的快速體驗訊息生產功能傳送一條內容為 hello eventbridge 的訊息到對應的主題中去。

21.png

接下來我們就可以發現,這條 RocketMQ 訊息,以 CloudEvent 的形式被投遞到了對應的服務中去,我們從而打通了訊息到事件的鏈路。同時,基於我們上述提到的分級儲存功能,訊息佇列 RocketMQ 轉變成了一個能夠源源不斷提供事件的資料倉儲,為整個事件生態提供了更加廣闊的場景。

事件驅動是未來商業組織和業務系統的重要趨勢,而訊息佇列 RocketMQ 會堅定地擁抱這一趨勢,將訊息融入到事件的生態中。

總結

我們選取了訊息佇列 RocketMQ 的幾個產品剖面,從多訊息型別、分級儲存到穩定性、可觀測性,再到面向未來的事件驅動,並結合與開源 RocketMQ 的對比,及具體應用場景的分析,為大家展示了基於訊息佇列 RocketMQ 的大型分散式應用上雲最佳實踐。

相關文章