中國移動蘇州研發中心消息隊列高可用設計之談 | SOFAStack 用戶說

文章摘要:BC-MQ 是中國移動蘇州研發中心結合自身在雲計算產品和技術的較多積累、自主研發的大雲消息隊列中間件產品,本文詳細解讀了 SOFAJRaft 在其消息雲服務中的最佳應用實踐。git

前言:

高可用的定義,指的是「一個系統通過特有的設計與改造,減小因不肯定故障停服的時間,從而對業務使用方來講能夠保證其服務的高度可用性」。在生產環境中,每每會存在不少不可預知的故障因素,好比虛擬機宕機、磁盤損壞和網絡故障等,所以系統自身的高可用是任何工業級產品所需重點考慮的因素。github

對於消息隊列服務來講,考慮到故障切換和業務感知等問題,傳統的高可用方式(冷備或者熱備)通常都不太適用。在通過多種技術方案對比後,咱們發現採用基於 Raft 共識算法的多副本設計方案能夠知足咱們產品的要求,所以在鑑權認證組件和API計量服務組件中,咱們集成了螞蟻金服開源的 SOFAJRaft 庫,實現這兩個組件應對單點故障的高可用。算法

GitHub 地址:github.com/sofastack/s…編程

1、背景知識:Raft 共識性算法是什麼?

Raft 是一種分佈式系統中易於理解的共識算法,該協議本質上是 Paxos 算法的精簡版,而不一樣的是依靠 Raft 模塊化的拆分以及更加簡化的設計,其實現起來更加容易和方便。[1]緩存

模塊化的拆分主要體如今 Raft 把一致性協議劃分爲以下幾部分:安全

  1. Leader 選舉;
  2. Membership 變動;
  3. 日誌複製;
  4. Snapshot。

而更加簡化的設計則體如今:Raft 不容許相似 Paxos 中的亂序提交、簡化系統中的角色狀態(算法定義 Leader、Follower 和 Candidate 三種角色)、限制僅 Leader 可寫入、採用隨機超時觸發 Leader Election 機制來避免「瓜分選票」等等。[2]性能優化

1.1 Raft 算法的總體結構概覽

Raft 算法的總體結構概覽

從上面的 Raft 算法總體結構圖中能夠看出,整個分佈式系統中同一時刻有且僅有一個 Leader 角色的節點(如圖最右邊的服務器),只有 Leader 節點能夠接受 Client 發送過來的請求。Leader 節點負責主動與全部 Follower 節點進行網絡通訊(如圖左邊兩個服務器),負責將本地的日誌發送給全部 Follower 節點,並收集分佈式系統中多數派的 Follower 節點的響應。此外,Leader 節點,還需向全部 Follower 節點主動發送心跳維持領導地位(即:保持存在感)。服務器

因此,只要各個節點上的日誌保持內容和順序是一致的,那麼節點上的狀態機就能以相同的順序執行相同的命令,這樣它們執行的結果也都是同樣的。網絡

1.2 Raft 算法的三種角色及轉換

  1. Follower:徹底被動,不能發送任何請求,只接受並響應來自 Leader 和 Candidate 的 Message,每一個節點啓動後的初始狀態通常都是 Follower;
  2. Leader:處理全部來自客戶端的請求、複製 Log 到全部 Follower,而且與 Follower 保持心跳請求;
  3. Candidate:節點競選 Leader 時的狀態。Follower 節點在參與選舉以前,會將本身的狀態轉換爲 Candidate。

Raft 算法的三種角色及轉換

1.3 任期與邏輯時鐘概念

任期與邏輯時鐘概念

  1. 時間被劃分爲多個任期 term(如同總統選舉同樣),term id 按時間軸單調遞增;
  2. 每個任期開始後要作的第一件事都是選舉 Leader 節點,選舉成功以後,Leader 負責在該任期內管理整個分佈式集羣,「日誌複製」、「經過心跳維護本身的角色」;
  3. 每一個任期至多隻有一個 Leader 節點,也可能沒有 Leader (因爲「分票」致使)。

1.4 Raft 算法的實際應用實現

目前,Raft 算法已經成熟地應用於諸多知名的開源項目中。業界很是著名的 Etcd(Kubernetes 高可用強一致性的服務發現組件)和 TiKV(高性能開源 KV 存儲)均是 Raft 算法的實現。架構

2、BC-MQ 基於 Raft 的高可用設計

爲知足企業上雲和構建萬物相連的物聯網業務需求,中國移動蘇州研發中心結合自身在雲計算產品和技術的較多積累,研發了大雲消息隊列中間件產品 BC-MQ。該產品基於 Apache 開源社區的 RocketMQ 內核,同時結合雲端 PAAS 產品架構和消息中間件的應用業務需求進行深度優化和定製化的研發,提供了一款能夠知足於雲端場景的高性能、高可靠、低延遲和高可用的工業級產品。

本節從解決原有高可用技術方案的問題視角出發,同時結合選型 SOFAJRaft 庫的原因,將詳細闡述 BC-MQ 產品中的安全認證和 API 計量採集服務的高可用設計方案(注:這裏不會涉及到安全認證和 API 計量採集組件自己的技術方案細節)。

2.1 GlusterFS+Keepalived 高可用方案與問題

1. GlusterFS+Keepalived 高可用設計方案

在BC-MQ原有的方案中,多組安全認證服務各自獨立部署組建集羣,各個安全認證服務相互獨立,沒有主從關聯,服務自己無狀態,可水平任意擴展。安全認證服務的高可用依賴於RPC通訊的客戶端保證,其主要經過負載均衡算法從安全認證服務集羣選擇一個節點發送RPC請求來實現租戶級鑑權認證元數據的獲取。在生產環境中,若是出現其中一個安全認證節點宕機不可用時,客戶端的RPC通訊層可以及時感知並從本地的Node列表中剔除不可用節點。

集羣中有狀態的租戶級安全認證元數據的強一致性由GlusterFS分佈式文件存儲的同步機制來保證。安全認證服務組建高可用集羣的具體設計方案圖以下所示:

安全認證服務組建高可用集羣的具體設計方案圖

而 BC-MQ 中 API 計量採集服務組件的高可用性則是依靠 Keepalived 組件的冷備模式結合 GlusterFS 分佈式文件存儲的同步機制共同保證,從而在必定程度上解決了 API 計量採集服務的單點不可用問題。API 計量採集服務的具體高可用設計方案圖以下所示:

image.png

2. GlusterFS+Keepalived 高可用方案遇到的問題

初步看上面的這種高可用技術方案挺完美的。可是通過驗證和仔細推敲後就發如今生產環境中可能會存在以下幾個問題:

  1. 上面所述的高可用設計方案中引入了 GlusterFS 分佈式文件存儲系統和 Keepalived 組件,這增長了系統總體的運維複雜度,給運維人員帶來不少人工介入排查和部署的工做負擔;另外一方面,GlusterFS 和 Keepalived 自己的可靠性、穩定性和性能指標等問題也須要軟件研發人員重點關注,這增長了系統總體設計的複雜度;
  2. 在實際的生產環境中,Keepalived 組件採用冷備方式做爲高可用方案須要考慮主機故障宕機後切換到備機的時間成本消耗。在這段時間內,API 計量服務是短暫不可用的。所以,Keepalived 組件的主備切換會形成業務感知影響,致使一些業務的風險發生。

2.2 基於 SOFAJRaft 庫的高可用設計方案

因爲「GlusterFS+Keepalived」的高可用方案存在上一節闡述的兩個問題,因此咱們考慮是否能夠採用其餘的高可用方案來解決這兩個問題?目標:即便生產環境出現部分節點故障後,安全認證和 API 計量組件依舊可以正常提供服務,作到業務無感知。

爲了實現當分佈式集羣中的部分節點出現故障停服後,集羣仍然可以自動選主繼續正常對外提供服務,使得故障對外部業務不會產生任何影響,同時高可用方案又不能依賴外部系統,那咱們也就想到了 Raft 算法。Raft 算法設計,簡潔易懂,沒有任何外部依賴,能夠完成一個高可靠、高可用、強一致的數據複製系統,解決咱們前面遇到的問題。

業界有一些 Raft 算法的實現,目前比較流行的主要有百度開源的Braft和螞蟻金服開源的 SOFAJRaft。從官方 Github 上對兩款開源 Raft 實現框架支持的功能和特性來看,基本相近,但 Braft 是 C/C++ 語言實現的,而 SOFAJRaft 是 JAVA 語言實現的,所以咱們從技術棧、集成難易和運維成本等角度綜合考慮,最終選擇了 SOFAJRaft。

1. 爲什麼技術選型 SOFAJRaft 庫?

SOFAJRaft 是一個基於 Raft 一致性算法的生產級高性能 JAVA 實現,支持 MULTI-RAFT-GROUP,適用於高負載低延遲的場景。使用 SOFAJRaft,使用者能夠更加專一於本身的業務領域,由 SOFAJRaft 負責處理全部與 Raft 算法相關的技術難題,而且 SOFAJRaft 比較易於使用,用戶能夠經過 Github 上的幾個示例在很短的時間內掌握並使用它。下面先簡單介紹下 SOFAJRaft 的特性和加強功能點:

SOFAJRaft 的特性和加強功能點

其中:

  1. Membership change 成員管理:集羣內成員的加入和退出不會影響集羣對外提供服務。
  2. Transfer leader:除了集羣根據算法自動選出 Leader 以外,還支持經過指令強制指定一個節點成爲 Leader。
  3. Fault tolerance 容錯性:當集羣內有節點由於各類緣由不能正常運行時,不會影響整個集羣的正常工做。
  4. 多數派故障恢復:當集羣內半數以上的節點都不能正常服務的時候,正常的作法是等待集羣自動恢復,不過 SOFAJRaft 也提供了 Reset 的指令,可讓整個集羣當即重建。
  5. Metrics:SOFAJRaft 內置了基於 Metrics 類庫的性能指標統計,具備豐富的性能統計指標,利用這些指標數據能夠幫助用戶更容易找出系統性能瓶頸。

SOFAJRaft 性能優化

爲了提供支持生產環境運行的高性能,SOFAJRaft 主要作了以下幾部分的性能優化,其中:

  1. 並行 append log:在 SOFAJRaft 中 Leader 本地持久化 Log 和向 Follower 發送 Log 是並行的。
  2. 併發複製 Leader 向全部 Follwers 發送 Log 也是徹底相互獨立和併發的。
  3. 異步化:SOFAJRaft 中整個鏈路幾乎沒有任何阻塞,徹底異步的,是一個徹底的 Callback 編程模型。

所以,綜上所述咱們最終選用 SOFAJRaft 的理由以下:

  1. SOFAJRaft 基於 JAVA 實現,可以很方便的與 BC-MQ 中安全認證服務和 API 計量服務組件進行集成。
  2. SOFAJRaft 做爲一個實現 Raft 協議的框架,提供了易於實現的狀態機接口,只須要實現它提供的接口便可完成高可用的改造。
  3. 從實際的驗證結果來講,SOFAJRaft 的性能和穩定性可以徹底知足甚至超過咱們的預期。
  4. SOFAJRaft 的功能性可以解決上面篇幅中 BC-MQ 原有「GlusterFS+Keepalived」高可用方案中所遇到的問題。

2.BC-MQ 組件集成 SOFAJRaft 的優化設計

BC-MQ在集成SOFAJRaft庫後在部署架構、數據持久化和高可用模式上都進行了能力升級,較好地解決了「GlusterFS+Keepalived」中的問題。

  1. 部署架構:集成SOFAJRaft庫後,BC-MQ的安全認證和API計量服務的高可用部署再也不依賴「GlusterFS+Keepalived」這兩個外部組件;安全認證和API計量服務組件按照配置文件獨立部署組成相應的RaftGroup便可對外提供服務;
  2. 數據持久化:數據的強一致性再也不依賴「GlusterFS分佈式文件存儲」。經過SOFAJRaft的日誌複製和狀態機,實現集羣中Leader節點和Follower節點的數據同步保證主備節點的數據一致性;
  3. 高可用模式:從原有的「KeepaLived冷備切換」轉變爲「Raft自動Leader選舉」,發生故障後,API計量服務仍然可以對外正常提供服務,故障轉移的過程無需運維人員介入;

組件服務端的狀態機接口實現

針對具體的業務應用而言(對 BC-MQ 來講,就是 API 計量統計和安全認證鑑權),狀態機(StateMachine)是業務邏輯實現的主要接口,狀態機運行在每一個Raft節點上,提交的 任務 Task 若是成功,最終都會複製應用到分佈式集羣中的每一個節點的狀態機上。

在 SOFAJRaft 中提供了一個已經具有絕大部分默認實現的抽象適配類— StateMachineAdapter,直接繼承它可使得業務應用避免實現全部的接口。咱們根據 BC-MQ 組件改造的需求,對部分接口作了以下的實現:

1.void onApply(Iterator iter):該方法是 SOFAJRaft 中最爲核心的接口。在整個分佈式集羣環境中,待同步的數據會封裝成 LogEntry 複製到其餘節點。在數據同步完成以後,進程會提交到自身狀態機的這個方法中執行。在 BC-MQ 中,API 計量採集服務在計量統計數據日誌同步至 Follower 節點後,SOFAJRaft 在業務狀態機的 onApply 方法中調用 API 計量採集服務組件的存儲接口進行持久化。

2.void onLeaderStart(long term)/void onLeaderStop(Status status):這個兩個方法是在節點經過選舉成爲 Leader 和失去 Leader 資格時調用,BC-MQ 的安全認證和 API 計量服務組件自己也維護了 Raft 的角色狀態(這裏的角色狀態與 SOFAJRaft 自己的是保持一致的)。在節點的角色發生轉變的時候,須要調用這個方法,將組件的角色和狀態轉變一致。這樣實現主要是與 BC-MQ 的業務場景相關,在集羣中通過從新選舉後節點角色轉變時,只有API 計量組件服務的 Leader 節點纔可以執行消息隊列的 API 計量採集相關的定時任務。

3.void onSnapshotSave(SnapshotWriter writer, Closure done)/boolean onSnapshotLoad(SnapshotReader reader):這兩個方法是 SOFAJRaft 快照相關的接口調用,快照自己的做用就是在有新的節點加入到 SOFAJRaft Group 時,不須要加載所有的 Log 日誌數據,而只須要從最近的 index 開始加載,這能夠節省從 Leader 節點同步大量日誌信息所形成的網絡通訊開銷。BC-MQ 的安全認證和 API 計量採集服務組件實現了這兩個方法,用於實現快照的特性。

客戶端請求重定向機制優化

SOFAJRaft 中默認只有 Leader 節點可以被客戶端訪問到,全部的日誌提交都須要先提交到集羣的 Leader 節點,而後由Leader節點同步到其餘的 Follower 節點。BC-MQ 的安全認證服務和 API 計量服務組件經過 SOFAJRaft 改造後,在 BC-MQ 中原有的客戶端 RPC 請求訪問方式也須要通過一些優化設計,爲了讓客戶端可以實時感知到分佈式集羣環境中當前的 Leader 節點,所以須要在客戶端緩存一個集羣的節點列表 NodeList 和 LeaderId。

僅僅在客戶端維護一個本地緩存還不夠,由於若是集羣中的 Leader 節點出現了宕機的故障時,集羣會發生從新選舉,那麼客戶端緩存的 Leader 節點信息就會過時,這就須要客戶端就可以感知到 Leader 節點的變化。爲解決這個問題,咱們採用了 RPC 請求重定向機制來保證,一旦RPC請求發送到了集羣中的 Follower 節點,那麼 Follower 會將該請求重定向到 Leader。如下爲 BC-MQ 客戶端通訊重定向機制優化設計圖:

定向機制優化設計圖

3、BC-MQ 的高可用與節點管理性驗證

下面展現的是 BC-MQ 的安全認證服務和 API 計量服務組件的部分測試用例,從用例的實際執行狀況來看,與咱們的預期結果徹底一致能夠知足生產環境高可用的業務場景。

序號 具體業務場景 預期結果 實際結果
1 安全認證組件3節點部署,Kill掉其中1個節點,客戶端持續發佈/訂閱帶鑑權的消息 安全認證組件Leader角色轉換,客戶端發佈/訂閱帶鑑權消息無任何影響 與預期一致
2 安全認證的5節點部署,Kill掉其中2個節點,客戶端持續發佈/訂閱帶鑑權的消息 安全認證組件Leader角色轉換,客戶端發佈/訂閱帶鑑權消息無任何影響 與預期一致
3 API計量組件3節點部署,Kill掉其1個節點,客戶端持續;發佈/訂閱帶鑑權的消息 API計量組件Leader角色轉換,輸出的API計量文件正確 與預期一致
4 API計量組件5節點部署,Kill掉其2個節點,客戶端持續發佈/訂閱帶鑑權的消息 API計量組件Leader角色轉換,輸出的API計量文件正確 與預期一致
5 在集羣中模擬出現網絡分區(對稱/非對稱)的場景,安全認證服務集羣是否會出現腦裂現象,鑑權認證數據是否正確 網絡分區(對稱/非對稱)場景下,集羣不會出現腦裂,而且鑑權數據是正確的 與預期一致
6 在集羣中模擬出現網絡分區(對稱/非對稱)的場景,API計量服務集羣是否會出現腦裂現象,API計量數據是否正確 網絡分區(對稱/非對稱)場景下,集羣不會出現腦裂,而且API計量數據是正確的 與預期一致
7 在3節點組成的安全認證服務集羣的負載工做的場景下,向該RaftGroup添加1/2節點,客戶端持續發佈/訂閱帶鑑權的消息 客戶端發佈/訂閱帶鑑權消息無任何影響 與預期一致
8 在5節點組成的安全認證服務集羣的負載工做的場景下,移除該RaftGroup中的1/2節點,客戶端持續發佈/訂閱帶鑑權的消息 客戶端發佈/訂閱帶鑑權消息無任何影響 與預期一致

4、總結

本文主要介紹了中國移動蘇州研發中心自主研發的 BC-MQ 產品中兩個重要組件—安全認證和 API 計量服務是如何經過集成開源的 SOFAJRaft 庫解決原來「GlusterFS+Keepalived」高可用方案中遇到的問題,以實現大規模消息隊列雲服務集羣的高可用部署優化方案。因爲文章篇幅的緣由,本文沒有對 BC-MQ 自己多項重要的特性進行詳細介紹,做者將在後續的文章中繼續進行闡述。同時,限於筆者的才疏學淺,對本文內容可能還有理解不到位的地方,若有闡述不合理之處還望留言一塊兒探討。

5、參考文獻

[1] Diego Ongaro and John Ousterhout.Raft Paper. 2013

[2] 詳解螞蟻金服 SOFAJRaft | 生產級高性能 Java 實現

做者介紹: 胡宗棠,中國移動蘇州研發中心雲計算中間件團隊負責人,Apache RocketMQ Committer,Linux OpenMessaging Advisory Borad Member,SOFAJRaft Contributor,熟悉分佈式消息中間件的設計原理、架構以及各類應用場景。

公衆號:金融級分佈式架構(Antfin_SOFA)

相關文章
相關標籤/搜索