計算儲存分離在京東雲訊息中介軟體JCQ上的應用

語言: CN / TW / HK

作者:田寄遠

JCQ全名JD Cloud Message Queue,是京東雲自研、具有CloudNative特性的分散式訊息中介軟體。 JCQ設計初衷即為適應雲特性的訊息中介軟體;具有高可用、資料可靠性、副本物理隔離、服務自治、健康狀態彙報、少運維或無運維、容器部署、彈性伸縮、租戶隔離、按量付費、雲賬戶體系、授權等特性。

演進過程

2017年中開始開發JCQ 1.0版本,2018年11月正式GA上線對外售賣,1.0版本中Topic受限於單臺伺服器限制,滿足不了使用者超大規格topic的需求。

2019年4月 JCQ 2.0 正式上線,主要新增特性是topic 擴縮容能力、熱點Topic在Broker間的負載均衡、熱點Broker的流量轉移。

2019年7月JCQ做了一次大的架構演進——計算儲存分離,大版本號為JCQ 3.0, 於2019年底上線。計算儲存分離對架構帶來了比較明顯的好處,解決了日常遇到許多的痛點問題。下文詳細介紹此次演進帶來的好處及解決的痛點問題。

升級影響範圍儘可能小

在JCQ2.0中計算模組與儲存模組處於同一個程序,升級計算模組勢必將儲存模組一起升級。而儲存模組重啟是比較重的動作,需要做的工作有:載入大量資料、進行訊息資料與訊息索引資料比對、髒資料截斷等操作。往往修復計算模組一個小的Bug,就需要做上述非常重的儲存模組重啟。而在現實工作中,大部分升級工作都是由於計算模組功能更新或Bugfix引起的。

為了解決這個問題, JCQ3.0將計算模組、儲存模組獨立部署,之間通過RPC呼叫。各自升級互不影響。如下圖所示:

計算節點Broker只負責生產訊息、推送訊息、鑑權、認證、限流、擁塞控制、客戶端負載均衡等業務邏輯,屬於無狀態服務。比較輕量,升級速度快。

儲存節點Store只負責資料寫入、副本同步、資料讀取。因為業務邏輯簡單,功能穩定後,除優化外基本無需改動,也就無需升級。

成本降低

JCQ是共享訊息中介軟體,使用者申請的是不同規格TPS的Topic,並不感知cpu、memory、disk等硬體指標。 所以,JCQ服務方需要考慮如何合理的使用這些硬體指標。

JCQ是容器部署,有多種型別的元件,這些元件對硬體的需求也是多樣化的,其中對資源消耗最多的是計算模組和儲存模組。在JCQ2.0版本計算模組和儲存模組部署在一起,選擇機型時要兼顧cpu、memory、disk等指標,機型要求單一,很難與其他產品線混合部署。即使是同一資源池,也存在因為排程順序,造成排程失敗的情況。如一臺機器剩餘資源恰好能排程一個需要大規格磁碟的A容器,但是因為B容器先被排程到這臺機器上,剩餘資源就不夠建立一個A容器,那這臺機器上的磁碟就浪費了。

JCQ3.0後,計算節點Broker,與儲存節點Store獨立部署。這兩個元件可以各自選擇適合自己業務的機型,部署在相應資源池中;最終,可以做到與其他產品混合部署,共用資源池水位,而不用獨自承擔資源水位線。

 

架構改進帶來的成本降低

JCQ3.0中計算節點Broker是無狀態服務,主從切換比較輕量,能在秒級完成故障轉移;且部署時考慮了物理裝置反親和,如跨Rack、跨AZ部署。所以,可以在可用性、資源成本之間做一定的權衡;如可以使用M:1方式做高可用冷備,而不必1:1的比例高可用冷備,進而達到節省硬體資源的目的。

 

解決Raft效能問題

JCQ 1.0 設計之初就採用Raft演算法,來解決服務高可用、資料一致性的問題。Message Log與Raft Log 有很多共同的特性,如順序寫、隨機讀、末端熱資料。所以,直接用Raft Log當成Message Log是非常合適的。

在JCQ演進中我們也發現了Raft本身的一些效能問題,如順序複製、順序commit、有的流程只能用單執行緒處理等限制。針對這些問題,最直接有效的辦法就是擴充套件Raft的數目、擴充套件單執行緒流程數目,在一定數量級內,併發能力隨著Raft Group數目的增長,呈線性增長關係,稱之MultiRaft,如下圖所示。



 

上圖中,每個StoreNode節點是一個獨立程序,內部有四組邏輯RaftGroup(橙色的節點為RaftGroup的Leader),各組RaftGroup之間是並行關係,可以做到Group間並行複製、並行commit。

由於大量使用了NIO,這些RaftGroup之間可以共享通訊執行緒池,擴充RaftGroup數目並不會帶來執行緒資源線性增長的問題。

快速故障恢復、輕量的負載均衡

在JCQ3.0中,Broker為輕量的無狀態服務,在主從切換、故障恢復方面相對2.0更為輕量,本身能更快的恢復對外服務能力。

同時,Broker將Producer、Consumer的連線請求,抽象為PubTask和SubTask,後文統稱為Task。Task的概念非常輕量,僅描述Client與Broker的對應關係,由元資料管理器Manager統一排程、管理。轉移Task只需要修改Task的內容,客戶端重新連線新Broker即可。

一般來說,Broker的主要瓶頸在於網路頻寬。Broker定期統計網路入口流量與出口流量,並上報給管理節點Manager。Manager根據入口流量、出口流量與頻寬閾值進行裁決,發現超過閾值後,通過一定策略將相應的Task轉移到較小負載的Broker上,並通知相應的Producer與Consumer;Producer與Consumer收到通知後,重新獲取Task的路由資訊,自動重連到新的Broker繼續進行生產、消費。

 

高扇出需求

設想一個場景,有一個大規格的topic,建立了n個消費組。消費總TPS是生產總TPS的n倍。增加消費組,會導致消費總TPS線性增長。到達一定消費組規模後,單Broker由於網絡卡頻寬的原因,無法滿足這種高扇出的場景。單伺服器是無法解決這個問題。

在JCQ 3.0 可以將這些不同的消費組對應的SubTask分散到若干個Broker上,每個Broker負責一部分SubTask,單Broker從Store預讀訊息,將資料推送給Consumer。這樣多個Broker共同完成所有消費組的訊息流量,協作一起提供高扇出的能力。

支援多種儲存引擎

訊息中介軟體很大的特點是:大部分場景下,熱資料都在末端,而回溯幾天之前的訊息這個功能是不常用的。所以,就有冷熱資料之分。

JCQ 計算節點設計了一層儲存抽象層Store Bridge 可以接入不同的儲存引擎,可以接入Remote Raft Cluster,或者分散式檔案系統WOS、或者S3。甚者可以將冷資料定期從昂貴的本地盤解除安裝到廉價的儲存引擎上。

副作用

相對於JCQ2.0,計算節點與儲存節點之間的通訊方式,由介面呼叫變為RPC呼叫,在延遲方面會有一定損失。經過測試,絕大部分延遲都在1ms左右,在大多數場景下 犧牲1ms左右的延遲並不會給業務帶來太大的影響。

後續發展規劃

JCQ後續會主要在多協議相容,按需自動擴縮容、雲原生等方面演進。

多協議相容

JCQ協議為私有協議,在引導使用者遷移方面有比較大的障礙。後續會抽離JCQ Kernel,外部提供不同的協議接入層。方便使用者從其他MQ接入JCQ。目前已相容RocketMQ協議,SQS協議

自動擴縮容

JCQ是共享訊息中介軟體,但缺少Serverless自動擴縮容的特性。每逢大促,如618,雙11,服貿會等重要活動。業務方很難預估自己的業務量峰值,或者估計不足,會造成topic限流等問題。如在保證JCQ服務本身能力情況下,能做到topic靈活的自動擴縮容,將對使用者有極大的幫助,起到真正的削峰填谷作用。

雲原生

支援在kubernetes環境部署與交付,提供原生的Operator,能夠快速的部署在k8s環境中,更好的交付私有云、混合雲專案。