Gossip協議 詳解

我們之前講的二階段提交協議和 Raft 算法,它們都需要全部節點或者大多數節點正常運行,才能穩定運行。假如我們希望自己的系統能在極端情況下(比如集羣中只有一個節點在運行)也能運行.我們要怎麼辦呢?

我們可以通過 Gossip 協議實現這個目標。

Gossip 協議,顧名思義,就像流言蜚語一樣,利用一種隨機、帶有傳染性的方式,將信息
傳播到整個網絡中,並在一定時間內,使得系統內的所有節點數據一致。對你來說,掌握這
個協議不僅能很好地理解這種最常用的,實現最終一致性的算法,也能在後續工作中得心應
手地實現數據的最終一致性。

我們先來了解Gossip 三板斧,因爲這是 Gossip 協議的核心內容,也是實現最終一致性的常用三種方法。然後以實際系統爲例,瞭解在實際系統中是如何實現反熵的。

Gossip 的三板斧

Gossip 的三板斧分別是:直接郵寄(Direct Mail)反熵(Anti-entropy)謠言傳播(Rumor mongering)

直接郵寄:就是直接發送更新數據,當數據發送失敗時,將數據緩存下來,然後重傳。從圖中你可以看到,節點 A 直接將更新數據發送給了節點 B、D。
在這裏插入圖片描述
直接郵寄雖然實現起來比較容易,數據同步也很及時,但可能會因爲緩存隊列滿了而丟數據。也就是說,只採用直接郵寄是無法實現最終一致性的

那如何實現最終一致性呢?答案就是反熵。本質上,反熵是一種通過異步修復實現最終一致性的方法。常見的最終一致性系統(比如Cassandra),都實現了反熵功能。

反熵指的是集羣中的節點,每隔段時間就隨機選擇某個其他節點,然後通過互相交換自己的所有數據來消除兩者之間的差異,實現數據的最終一致性:
在這裏插入圖片描述

從圖 2 中你可以看到,節點 A 通過反熵的方式,修復了節點 D 中缺失的數據。那具體怎麼實現的呢?

其實,在實現反熵的時候,主要有推拉三種方式。我將以修復下圖中,2 個數據副本的不一致爲例,具體帶你瞭解一下。
在這裏插入圖片描述

推方式,就是將自己的所有副本數據,推給對方,修復對方副本中的熵:
在這裏插入圖片描述

拉方式,就是拉取對方的所有副本數據,修復自己副本中的熵:

在這裏插入圖片描述
理解了推和拉之後,推拉這個方式就很好理解了,這個方式就是同時修復自己副本和對方副本中的熵:
在這裏插入圖片描述

也許你們會覺得反熵是一個很奇怪的名詞。其實,你可以這麼來理解,反熵中的熵是指混亂程度,反熵就是指消除不同節點中數據的差異,提升節點間數據的相似度,降低熵值。

另外需要注意的是,因爲反熵需要節點兩兩交換和比對自己所有的數據,執行反熵時通訊成本會很高,所以我不建議你在實際場景中頻繁執行反熵,並且可以通過引入校驗和(Checksum)等機制,降低需要對比的數據量和通訊消息等。

雖然反熵很實用,但是執行反熵時,相關的節點都是已知的,而且節點數量不能太多,如果是一個動態變化或節點數比較多的分佈式環境(比如在 DevOps 環境中檢測節點故障,並動態維護集羣節點狀態),這時反熵就不適用了。那麼當你面臨這個情況要怎樣實現最終一
致性呢?答案就是謠言傳播。

謠言傳播,廣泛地散播謠言,它指的是當一個節點有了新數據後,這個節點變成活躍狀態,並週期性地聯繫其他節點向其發送新數據,直到所有的節點都存儲了該新數據:

在這裏插入圖片描述

從圖中你可以看到,節點 A 向節點 B、D 發送新數據,節點 B 收到新數據後,變成活躍節點,然後節點 B 向節點 C、D 發送新數據。其實,謠言傳播非常具有傳染性,它適合動態變化的分佈式系統。

如何使用 Anti-entropy 實現最終一致

在分佈式存儲系統中,實現數據副本最終一致性,最常用的方法就是反熵了。爲了幫你徹底理解和掌握在實際環境中實現反熵的方法,我們以自研 InfluxDB 的反熵實現爲例,具體帶你瞭解一下。

在自研 InfluxDB 中,一份數據副本是由多個分片組成的,也就是實現了數據分片,三節點三副本的集羣,就像下圖的樣子:

在這裏插入圖片描述

反熵的目標是確保每個 DATA 節點擁有元信息指定的分片,而且不同節點上,同一分片組中的分片都沒有差異。比如說,節點 A 要擁有分片 Shard1 和 Shard2,而且,節點 A 的Shard1 和 Shard2,與節點 B、C 中的 Shard1 和 Shard2,是一樣的。

那麼,在 DATA 節點上,存在哪些數據缺失的情況呢?也就說,我們需要解決哪些問題呢?

我們將數據缺失,分爲這樣 2 種情況。

  • 缺失分片:也就是說,在某個節點上整個分片都丟失了。
  • 節點之間的分片不一致:也就是說,節點上分片都存在,但裏面的數據不一樣,有數據丟失的情況發生。

第一種情況修復起來不復雜,我們只需要將分片數據,通過 RPC 通訊,從其他節點上拷貝過來就可以了:
在這裏插入圖片描述

需要注意的是第二種情況,因爲第二種情況修復起來要複雜一些。我們需要設計一個閉環的流程,按照一個順序修復,執行完流程後,也就是實現了一致性了。具體是怎麼設計的呢?

它是按照一定順序來修復節點的數據差異,先隨機選擇一個節點,然後循環修復,每個節點生成自己節點有、下一個節點沒有的差異數據,發送給下一個節點,進行修復(爲了方便演示,假設 Shard1、Shard2 在各節點上是不一致的):

在這裏插入圖片描述

從圖中你可以看到,數據修復的起始節點爲節點 A,數據修復是按照順時針順序,循環修復的。需要你注意的是,最後節點 A 又對節點 B 的數據執行了一次數據修復操作,因爲只有這樣,節點 C 有、節點 B 缺失的差異數據,纔會同步到節點 B 上。學到這裏你可以看到,在實現反熵時,實現細節和最初算法的約定有些不同。比如,不是一個節點不斷隨機選擇另一個節點,來修復副本上的熵,而是設計了一個閉環的流程,一次修復所有節點的副本數據不一致。

爲什麼這麼設計呢?因爲我們希望能在一個確定的時間範圍內實現數據副本的最終一致性,而不是基於隨機性的概率,在一個不確定的時間範圍內實現數據副本的最終一致性。

這樣做能減少數據不一致對監控視圖影響的時長。而我希望你能注意到,技術是要活學活用的,要能根據場景特點權衡妥協,設計出最適合這個場景的系統功能。最後需要你注意的是,因爲反熵需要做一致性對比,很消耗系統性能,所以建議你將是否啓用反熵功能、執行一致性檢測的時間間隔等,做成可配置的,能在不同場景中按需使用。

小結

在實際場景中,實現數據副本的最終一致性時,一般而言,直接郵寄的方式是一定要實現的,因爲不需要做一致性對比,只是通過發送更新數據或緩存重傳,來修復數據的不一致,性能損耗低。在存儲組件中,節點都是已知的,一般採用反熵修復數據副本的一致性。當集羣節點是變化的,或者集羣節點數比較多時,這時要採用謠言傳播的方式,同步更新數據,實現最終一致。

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