乾貨分享 | 深度解析雲原生訊息佇列 AMQP

ApachePulsar發表於2021-12-09

編者薦語:

文章作者為中國移動雲能力中心,文章轉載已授權。本文將詳細解析基於 Apache Pulsar 的雲原生訊息佇列 AMQP 背景與整體設計等深度內容。

以下文章來源於蘇研大雲人,作者雲原生中介軟體團隊


友情提示:全文5000多文字,預計閱讀時間3分鐘

一、自研訊息佇列中介軟體AMQP的背景

隨著公司公有云業務持續發展和使用者數量的不斷增長,資料量和請求量也在急劇增長,訊息佇列作為必不可少的通訊元件,面臨的壓力也在日益增長。在對訊息佇列的元件維護中我們發現:OpenStack使用的訊息佇列RabbitMQ存在一些問題,比如訊息易丟失,叢集穩定性差,問題排查困難等。諸多難以解決的問題使我們萌生了尋求替代開源RabbitMQ訊息佇列的想法;另一方面,主流雲服務廠商,如阿里雲、華為雲、天翼雲等均已提供AMQP協議支援的訊息佇列產品,而我們缺少自研對標產品。基於以上兩點,團隊開始自研一款高效能、高可靠、高穩定,支援AMQP協議的訊息佇列產品。

我們的需求

綜合雲上產品和移動雲元件的需求,整理了訊息佇列AMQP的幾大核心需求如下:

  1. 具備高吞吐量,低延遲,高可靠的能力;
  2. 能根據需求進行無限制的擴容,縮容;
  3. 對於上雲產品來說,需要具備多租戶隔離的能力;
  4. 具備海量訊息堆積能力,並且訊息的堆積不會影響效能和穩定性;
  5. 支援AMQP協議,相容AMQP協議的客戶端(比如,開源RabbitMQ SDK);
  6. 具備運維部署能力,資料遷移的便利性,具備高效的叢集部署、遷移效率。

開源產品調研

在產品設計之初,研發團隊主要調研了兩款實現了AMQP協議的開源產品:RabbitMQ和Qpid。由於Qpid在效能方面表現不佳被排除在外,RabbitMQ效能高、使用範圍廣,但是不符合我們的需求使用場景,有如下幾個原因:

  1. 持久化訊息效能較差。為了保證訊息不丟失且訊息可回溯,需要將訊息持久化儲存,經過測試RabbitMQ的持久化訊息效能較差,不滿足我們的需求,詳見第四章節的效能測試對比。
  2. 為了保證訊息不丟失,可以使用RabbitMQ的映象佇列,映象佇列的機制就是訊息多副本儲存在多節點的記憶體中,經過測試發現,在開啟映象佇列的場景下,會出現兩方面的問題:首先是叢集穩定性較差,其次是訊息堆積會導致記憶體溢位。
  3. 問題排查的困難性,RabbitMQ的程式語言是Erlang,這種程式語言較為小眾。RabbitMQ的原始碼晦澀難懂,導致出現問題時,排查困難,且RabbitMQ沒有實時訊息追蹤的能力,需要開啟訊息追蹤的外掛,無法及時回溯出現問題的訊息。

基於以上原因,我們開始訊息佇列AMQP的自研。

二、訊息佇列AMQP整體設計

計算儲存分離的架構

考慮到高穩定性、高可靠性和高吞吐量等諸多設計目標,研發團隊最終決定採用符合雲原生設計理念的計算儲存分離架構。

計算儲存耦合和計算儲存分離有如下幾個方面的對比:

當儲存和計算耦合在一個叢集中時,存在如下的一些問題:

  1. 在不同的應用或者發展時期,需要不同的儲存空間和計算能力配比,使得機器的選型會比較複雜;
  2. 當儲存空間或計算資源不足時,只能同時對兩者進行擴容,導致擴容的經濟效率比較低(另一種擴容的資源被浪費了);
  3. 在雲端計算場景下,不能實現真正的彈性計算,因為計算叢集中也有資料,關閉閒置的計算叢集會丟失資料。

針對計算儲存耦合帶來的一些問題,研發團隊也調研了具有計算儲存分離能力的開源訊息佇列Apache Pulsar。

在Pulsar的架構中,計算和資料儲存是單獨的兩個元件:

計算層也就是Broker,Pulsar的Broker不直接儲存訊息實體資料,主要負責處理Consumer和Producer相關的連線請求處理等,如果業務上Consumer和Producer特別的多,可以單獨擴充套件這一層。

資料儲存也就是Bookie,Pulsar使用了Apache BookKeeper作為儲存支援,BookKeeper是一個提供日誌條目流儲存持久化的服務框架,計算層使用時不必過多的關心儲存細節。

結合訊息佇列AMQP的應用場景以及分析面向的客戶群體,我們選擇Pulsar這種計算儲存分離的訊息佇列作為原型進行訊息佇列AMQP的定製化開發。在調研Pulsar以及與Puslar社群深入溝通之後發現Pulsar現有的Protocol Handler機制非常符合我們這種定製化開發的需求,Protocol Handler協議處理外掛可以利用Pulsar 現有的一些元件(例如 服務發現元件-Topic LookUp、分散式日誌庫-ManagedLedger、消費進度管理元件-Cursor 等)來幫助我們實現一些邏輯處理。

因此Pulsar的Protocol Handler就成為了我們訊息佇列AMQP定製化開發的基礎。更多Protocol Handler的介紹可參考Pulsar PIP-41。

(https://github.com/apache/pul...

訊息佇列AMQP整體架構如上圖所示,開發的重點就在於AMQP Protocol Handler的通訊層協議的解析處理、AMQP 0-9-1協議模型與Pulsar模型之間的對映、多租戶的支援以及最核心的傳送消費流程的處理。

核心功能點設計

  • 訊息的儲存

訊息佇列AMQP的儲存設計借鑑了RabbitMQ,最終實現利用Pulsar的PersistentTopic來實現具體的實體資料以及索引資料的儲存。

1、RabbitMQ的訊息儲存模型

RabbitMQ的訊息持久化實際包括兩部分:佇列索引(rabbit_queue_index)和訊息儲存(rabbit_msg_store)。

rabbit_queue_index負責維護佇列中落盤訊息的資訊,包括訊息的儲存位點、是否已經提交給消費者、是否已被消費者ACK等,每個佇列都有一個與之對應的rabbit_queue_index。

rabbit_msg_store以鍵值對的形式儲存訊息,每個節點有且只有一個,該節點上的所有佇列共享該檔案。從技術層面講rabbit_msg_store又可以分為msg_store_persistent和msg_store_transient,其中msg_store_persistent負責持久化訊息的儲存,不會丟失;而msg_store_transient負責非持久化訊息的儲存,重啟後訊息會丟失。

2、BookKeeper提供儲存支援

Pulsar broker中的ManagedLedger實現了對BookKeeper儲存層的封裝,利用ManagedLedger可以實現訊息的持久化、讀取以及消費進度管理。

3、如何利用Pulsar現有的模型實現exchange以及queue的對應

AMQP 0-9-1引入了一些基礎概念,例如 Exchagne, Queue 和 Router。這些與 Pulsar 的模型有著較大的區別。因此,我們需要採用一種建模對映方式,將現有Pulsar中對於Topic的釋出/訂閱模型與AMQP通訊協議中的業務模型對映到一起。

AmqpExchange

AmqpExchange 包含一個原始訊息 Topic,用來儲存 AMQP Producer 傳送的訊息。AmqpExchange 的 Replicator 會將訊息處理到 AMQP 佇列中。Replicator 是基於 Pulsar 的持久化遊標,可以確保成功將訊息傳送到佇列,而不會丟失訊息。

AmqpMessageRouter

AmqpMessageRouter 用於維護訊息路由型別以及將訊息從 AmqpExchange 路由到 AmqpQueue 的路由規則。路由型別和路由規則這些後設資料都持久化在 Pulsar 的ManagedLedger 中。所以就算 Broker 重啟,我們也可以恢復 AmqpMessageRouter。

AmqpQueue

AmqpQueue 提供一個索引訊息 Topic,用來儲存路由到這個佇列的 IndexMessage。IndexMessage 由原始訊息的 ID 和儲存訊息的 Exchange 的名稱組成。當 AmqpQueue 向 Consumer 傳送訊息時,AmqpQueue 會根據 IndexMessage 讀取原始訊息資料,然後將其傳送給 Consumer。

  • 多租戶的支援

作為一種企業級的訊息系統,Pulsar 的多租戶能力可滿足下列需求:

  • 保證不同租戶之間的隔離
  • 針對資源利用率強制實施配額
  • 提供每租戶和系統級的安全性
  • 確保低成本運維以及儘可能簡單的管理

Pulsar多租戶的特性,在topic的URL對映上充分顯現,結構如下:

AMQP 0-9-1的協議定義中,VirtualHost是資源隔離的基本單位,和Pulsar的這種多層級的模型不能有完全一致的對應關係,在我們的實現中,移動雲AMQP訊息佇列引入了Instance的概念,對應到Pulsar中的Tenant,元件版本使用固定的Tenant,Pulsar中的Namespace則對應到AMQP中的VirtualHost。其中元件版本的對應圖如下所示:

  • 訊息流轉過程

  1. 當 Producer 傳送訊息到 AmqpExchange,AmqpExchange 將訊息持久化到 Pulsar Topic (我們稱之為儲存原始訊息的 Topic)。
  2. AmqpExchange 的 Replicator 會將訊息傳遞給 Router。
  3. Router 判斷是否需要將訊息路由給 AmqpQueue。如果是,會將原始訊息的 ID 存入AmqpQueue 的 Topic 中 (我們稱之為儲存索引訊息的 Topic)。
  4. AmqpQueue 將訊息傳遞給 Consumer。

三、訊息佇列AMQP和RabbitMQ比較

雲原生

雲原生的"原生"即軟體設計之初就考慮到了在雲端部署的可能,訊息佇列AMQP採用計算儲存分離的核心架構,能夠充分利用分散式、彈性伸縮的雲端資源。

傳統架構下的訊息佇列如RabbitMQ,將訊息儲存在本地,Broker元件需承擔訊息分發和儲存的雙重功能;這使得Broker並非無狀態服務,不具備彈性伸縮的能力。

而自研訊息佇列AMQP通過計算儲存分離的架構,將Broker的角色進一步拆分為用於訊息分發的Broker和用於訊息儲存的Bookie,從而將Broker打造成無狀態服務,以實現Broker的彈性伸縮。

訊息可靠性

訊息的不丟失通常由兩個方面保障:首先訊息需要持久化到磁碟中,其次持久化訊息需要儲存多副本以提升訊息佇列的容錯能力。相較於訊息佇列RabbitMQ,自研AMQP在訊息可靠性的保障方面具有以下優勢:

RabbitMQ持久化訊息採用非同步刷盤機制,無法保障斷電、硬體故障等極端情況下資料的不丟失;訊息佇列AMQP原生支援訊息同步刷盤,可以保障除磁碟損壞的任何極端故障場景下,訊息的不丟失。

RabbitMQ僅在開啟映象佇列時才能夠進行訊息的多副本同步;而訊息佇列AMQP原生支援訊息的多副本儲存,部分節點磁碟損壞情況下,資料也能夠從副本中恢復出來。

RabbitMQ在開啟訊息持久化和映象佇列時,效能很差,無法滿足高效能的需求;而訊息佇列AMQP通過檔案的順序讀取和訊息的快取機制,仍能保證極高的效能。

容錯

容錯指叢集中部分節點發生故障的時候,叢集的可用性。

RabbitMQ的容錯性不高,在發生網路分割槽的情況下,會導致資料丟失和叢集的不可用,尤其是在配置映象佇列的情況下。

而訊息佇列AMQP各個元件都可以獨立的容錯。Broker是無狀態服務,當發生錯誤的時候,Queue就會轉移到其他Broker,不會影響訊息收發。Bookie雖然有狀態,但是並無主從之分,只要訊息的副本足夠多,即使部分Bookie當機或者不可用的情況下,服務依然可以正常執行。

可維護性

相較於RabbitMQ,自研AMQP提供更加完善的運維監控系統,對於系統的各項指標,比如TPS、容量、連線狀態、消費者狀態等各項指標均有詳細的監控,同時提供完善的說明文件以應對可能出現的各類問題,便於故障排查。

RabbitMQ不具備實時訊息追蹤能力,無法及時回溯出現問題的訊息;而AMQP具備訊息追蹤的功能,保障所有訊息可追溯,為問題的排查提供了便利。

RabbitMQ採用Erlang語言,較為小眾且晦澀難懂,很難進行原始碼級別的問題排查;而AMQP為自研中介軟體,所有問題都可以通過程式碼分析排查解決。

四、效能

在同樣的環境下,對訊息佇列AMQP和RabbitMQ的單機效能進行測試:

訊息體大小:1KB

exchange數量:1個

queue數量:1個

訊息是否持久化:是

通過建立1個Queue,1個Exchange,傳送1KB的訊息,對比訊息佇列AMQP和RabbitMQ的效能,得到上述的折線圖,從上圖可以看出,在同等測試條件下,訊息佇列AMQP的效能表現遠高於RabbitMQ。

五、總結

目前訊息佇列AMQP已經正式上線移動雲,歡迎大家訂購使用。

https://ecloud.10086.cn/home/...

另外訊息佇列AMQP元件版本替換OpenStack中RabbitMQ也已經完成測試環境的驗證工作,後續會在移動雲生產環境中作為OpenStack元件的通訊元件使用。

參考資料

1、Apache Pulsar 官網:https://pulsar.apache.org/doc...

2、《RabbitMQ 實戰指南》

END


作者簡介

張浩

中國移動雲能力中心中介軟體開發工程師,訊息佇列AMQP研發負責人,在訊息中介軟體以及分散式快取領域有豐富的經驗。

王少傑

中國移動雲能力中心軟體開發工程師,主要負責移動雲訊息佇列產品研發、效能調優和維護工作,在RocketMQ,Pulsar,RabbitMQ等方面有豐富的實踐和優化經驗。

歡迎投稿

Apache Pulsar 社群歡迎大家踴躍投稿,希望這裡成為大家獲取 Pulsar 經驗與知識分享的平臺,並幫助更多的社群小夥伴深入瞭解 Pulsar。掃碼新增 Bot 好友即可聯絡投稿?

點選連結訪問原文。

相關文章