Raft算法詳解(三)解決成員變更的問題

在日常工作中,可能會遇到服務器故障的情況,這時就需要替換集羣中的服務器。如果 遇到需要改變數據副本數的情況,則需要增加或移除集羣中的服務器。總的來說,在日常工 作中,集羣中的服務器數量是會發生變化的。

講到這兒,也許你會問:“Raft 是共識算法,對集羣成員進行變更時(比如增加 2 臺服務器),會不會因爲集羣分裂,出現 2 個領導者呢?”

在我看來,的確會出現這個問題,因爲 Raft 的領導者選舉,建立在“大多數”的基礎之 上,那麼當成員變更時,集羣成員發生了變化,就可能同時存在新舊配置的 2 個“大多數”,出現 2 個領導者,破壞了 Raft 集羣的領導者唯一性,影響了集羣的運行。

而關於成員變更,不僅是 Raft 算法中比較難理解的一部分,非常重要,也是 Raft 算法中 唯一被優化和改進的部分。比如,初實現成員變更的是聯合共識(Joint Consensus), 但這個方法實現起來難,後來 Raft 的作者就提出了一種改進後的方法,單節點變更 (single-server changes)

今天除了瞭解成員變更問題的本質之外,還會講一下如何通 過單節點變更的方法,解決成員變更的問題。學完本講內容之後,你不僅能理解成員變更的 問題和單節點變更的原理,也能更好地理解 Raft 源碼實現,掌握解決成員變更問題的方 法。

在開始今天內容之前,我先介紹一下“配置”這個詞兒。因爲常聽到有人說,自己不理解 配置(Configuration)的含義,從而不知道如何理解論文中的成員變更。

的確,配置是成員變更中一個非常重要的概念,我建議你這麼理解:它就是在說集羣是哪些 節點組成的,是集羣各節點地址信息的集合。比如節點 A、B、C 組成的集羣,那麼集羣的 配置就是[A, B, C]集合。

理解了這一點之後,咱們先來看一道思考題。

假設我們有一個由節點 A、B、C 組成的 Raft 集羣,現在我們需要增加數據副本數,增加 2 個副本(也就是增加 2 臺服務器),擴展爲由節點 A、B、C、D、E, 5 個節點組成的新集 羣:

在這裏插入圖片描述

那麼 Raft 算法是如何保障在集羣配置變更時,集羣能穩定運行,不出現 2 個領導者呢?帶 着這個問題,我們正式進入今天的學習。

老話說得好,“認識問題,才能解決問題”。爲了幫你更好地理解單節點變更的方法,我們 先來看一看,成員變更時,到底會出現什麼樣的問題?

成員變更的問題

在集羣中進行成員變更的大風險是,可能會同時出現 2 個領導者。比如在進 行成員變更時,節點 A、B 和 C 之間發生了分區錯誤,節點 A、B 組成舊配置中的“大多 數”,也就是變更前的 3 節點集羣中的“大多數”,那麼這時的領導者(節點 A)依舊是 領導者。

另一方面,節點 C 和新節點 D、E 組成了新配置的“大多數”,也就是變更後的 5 節點集 羣中的“大多數”,它們可能會選舉出新的領導者(比如節點 C)。那麼這時,就出現了同 時存在 2 個領導者的情況。

在這裏插入圖片描述

如果出現了 2 個領導者,那麼就違背了“領導者的唯一性”的原則,進而影響到集羣的穩 定運行。你要如何解決這個問題呢?

因爲我們在啓動集羣時,配置是固定的,不存在成員變更,在這種情況下,Raft 的領導者 選舉能保證只有一個領導者。也就是說,這時不會出現多個領導者的問題,那我可以先將集 羣關閉再啓動新集羣啊。也就是先把節點 A、B、C 組成的集羣關閉,然後再啓動節點 A、 B、C、D、E 組成的新集羣。

在我看來,這個方法不可行。 爲什麼呢?因爲你每次變更都要重啓集羣,意味着在集羣變 更期間服務不可用,肯定不行啊,太影響用戶體驗了。想象一下,你正在玩王者榮耀,時不 時彈出一個對話框通知你:系統升級,遊戲暫停 3 分鐘。這體驗糟糕不糟糕?

既然這種方法影響用戶體驗,根本行不通,那到底怎樣解決成員變更的問題呢?最常用的方 法就是單節點變更。

如何通過單節點變更解決成員變更的問題?

單節點變更,就是通過一次變更一個節點實現成員變更。 如果需要變更多個節點,那你需要 執行多次單節點變更。比如將 3 節點集羣擴容爲 5 節點集羣,這時你需要執行 2 次單節點 變更,先將 3 節點集羣變更爲 4 節點集羣,然後再將 4 節點集羣變更爲 5 節點集羣,就像 下圖的樣子。
在這裏插入圖片描述

現在,讓我們回到開篇的思考題,看看如何用單節點變更的方法,解決這個問題。爲了演示 方便,我們假設節點 A 是領導者:

在這裏插入圖片描述

目前的集羣配置爲[A, B, C],我們先向集羣中加入節點 D,這意味着新配置爲[A, B, C, D]。 成員變更,是通過這麼兩步實現的:

第一步,領導者(節點 A)向新節點(節點 D)同步數據;

第二步,領導者(節點 A)將新配置[A, B, C, D]作爲一個日誌項,複製到新配置中所有 節點(節點 A、B、C、D)上,然後將新配置的日誌項提交到本地狀態機,完成單節點 變更。

在這裏插入圖片描述

在變更完成後,現在的集羣配置就是[A, B, C, D],我們再向集羣中加入節點 E,也就是說, 新配置爲[A, B, C, D, E]。成員變更的步驟和上面類似:

第一步,領導者(節點 A)向新節點(節點 E)同步數據;

第二步,領導者(節點 A)將新配置[A, B, C, D, E]作爲一個日誌項,複製到新配置中的 所有節點(A、B、C、D、E)上,然後再將新配置的日誌項提交到本地狀態機,完成單 節點變更。

在這裏插入圖片描述

這樣一來,我們就通過一次變更一個節點的方式,完成了成員變更,保證了集羣中始終只有 一個領導者,而且集羣也在穩定運行,持續提供服務

我想說的是,在正常情況下,不管舊的集羣配置是怎麼組成的,舊配置的“大多數”和新配 置的“大多數”都會有一個節點是重疊的。 也就是說,不會同時存在舊配置和新配置 2 個“大多數”:

在這裏插入圖片描述
在這裏插入圖片描述

從上圖中你可以看到,不管集羣是偶數節點,還是奇數節點,不管是增加節點,還是移除節 點,新舊配置的“大多數”都會存在重疊(圖中的橙色節點)。

需要你注意的是,在分區錯誤、節點故障等情況下,如果我們併發執行單節點變更,那麼就 可能出現一次單節點變更尚未完成,新的單節點變更又在執行,導致集羣出現 2 個領導者 的情況。

如果你遇到這種情況,可以在領導者啓動時,創建一個 NO_OP 日誌項(也就是空日誌 項),只有當領導者將 NO_OP 日誌項提交後,再執行成員變更請求。這個解決辦法,你 記住就可以了,可以自己在試着研究下

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