Consul實現原理系列文章2: 用Gossip來做集羣成員管理和消息廣播

工作中用到了Consul來做服務發現,之後一段時間裏,我會陸續發一些文章來講述Consul實現原理。這篇文章會講述Consul是如何使用Gossip來做集羣成員管理和消息廣播的。

Consul使用Gossip協議來管理集羣中的成員關係,以及把消息廣播到集羣中。而這些Gossip的特性是利用Serf這個lib來實現的。

下面,我們先來看看什麼是Gossip協議。

Gossip協議

在學習Gossip的過程中,我找到了一篇介紹Gossip的很不錯的文章,下面是那篇文章的主要內容:

( 以下轉載自http://blog.csdn.net/chen77716/article/details/6275762):

Gossip背景

Gossip算法如其名,靈感來自辦公室八卦,只要一個人八卦一下,在有限的時間內所有的人都會知道該八卦的信息,這種方式也與病毒傳播類似,因此Gossip有衆多的別名“閒話算法”、“疫情傳播算法”、“病毒感染算法”、“謠言傳播算法”。

但Gossip並不是一個新東西,之前的泛洪查找、路由算法都歸屬於這個範疇,不同的是Gossip給這類算法提供了明確的語義、具體實施方法及收斂性證明。

Gossip特點

Gossip算法又被稱爲反熵(Anti-Entropy),熵是物理學上的一個概念,代表雜亂無章,而反熵就是在雜亂無章中尋求一致,這充分說明了Gossip的特點:在一個有界網絡中,每個節點都隨機地與其他節點通信,經過一番雜亂無章的通信,最終所有節點的狀態都會達成一致。每個節點可能知道所有其他節點,也可能僅知道幾個鄰居節點,只要這些節可以通過網絡連通,最終他們的狀態都是一致的,當然這也是疫情傳播的特點。

要注意到的一點是,即使有的節點因宕機而重啓,有新節點加入,但經過一段時間後,這些節點的狀態也會與其他節點達成一致,也就是說,Gossip天然具有分佈式容錯的優點。

Gossip本質

Gossip是一個帶冗餘的容錯算法,更進一步,Gossip是一個最終一致性算法。雖然無法保證在某個時刻所有節點狀態一致,但可以保證在”最終“所有節點一致,”最終“是一個現實中存在,但理論上無法證明的時間點。

因爲Gossip不要求節點知道所有其他節點,因此又具有去中心化的特點,節點之間完全對等,不需要任何的中心節點。實際上Gossip可以用於衆多能接受“最終一致性”的領域:失敗檢測、路由同步、Pub/Sub、動態負載均衡。

但Gossip的缺點也很明顯,冗餘通信會對網路帶寬、CUP資源造成很大的負載,而這些負載又受限於通信頻率,該頻率又影響着算法收斂的速度,後面我們會講在各種場合下的優化方法。

Gossip節點的通信方式及收斂性

根據原論文,兩個節點(A、B)之間存在三種通信方式:

  1. push: A節點將數據(key,value,version)及對應的版本號推送給B節點,B節點更新A中比自己新的數據
  2. pull:A僅將數據key,version推送給B,B將本地比A新的數據(Key,value,version)推送給A,A更新本地
  3. push/pull:與pull類似,只是多了一步,A再將本地比B新的數據推送給B,B更新本地

如果把兩個節點數據同步一次定義爲一個週期,則在一個週期內,push需通信1次,pull需2次,push/pull則需3次,從效果上來講,push/pull最好,理論上一個週期內可以使兩個節點完全一致。直觀上也感覺,push/pull的收斂速度是最快的。

假設每個節點通信週期都能選擇(感染)一個新節點,則Gossip算法退化爲一個二分查找過程,每個週期構成一個平衡二叉樹,收斂速度爲O(n2 ),對應的時間開銷則爲O(logn )。這也是Gossip理論上最優的收斂速度。

但在實際情況中最優收斂速度是很難達到的,假設某個節點在第i個週期被感染的概率爲pi ,第i+1個週期被感染的概率爲pi+1 ,則pull的方式:
這裏寫圖片描述

而push爲:
這裏寫圖片描述

顯然pull的收斂速度大於push,而每個節點在每個週期被感染的概率都是固定的
p(0< p <1),因此Gossip算法是基於p的平方收斂,也成爲概率收斂,這在衆多的一致性算法中是非常獨特的。

Gossip的節點的工作方式又分兩種:

  1. Anti-Entropy(反熵):以固定的概率傳播所有的數據
  2. Rumor-Mongering(謠言傳播):僅傳播新到達的數據

Anti-Entropy模式有完全的容錯性,但有較大的網絡、CPU負載;Rumor-Mongering模式有較小的網絡、CPU負載,但必須爲數據定義”最新“的邊界,並且難以保證完全容錯,對失敗重啓且超過”最新“期限的節點,無法保證最終一致性,或需要引入額外的機制處理不一致性。我們後續着重討論Anti-Entropy模式的優化。

Anti-Entropy的協調機制

協調機制是討論在每次2個節點通信時,如何交換數據能達到最快的一致性,也即消除兩個節點的不一致性。上面所講的push、pull等是通信方式,協調是在通信方式下的數據交換機制。

協調所面臨的最大問題是,因爲受限於網絡負載,不可能每次都把一個節點上的數據發送給另外一個節點,也即每個Gossip的消息大小都有上限。在有限的空間上有效率地交換所有的消息是協調要解決的主要問題。

在討論之前先聲明幾個概念:
令N = {p,q,s,…}爲需要gossip通信的server集合,有界大小
令(p1,p2,…)是宿主在節點p上的數據,其中數據有(key,value,version)構成,q的規則與p類似。

爲了保證一致性,規定數據的value及version只有宿主節點才能修改,其他節點只能間接通過Gossip協議來請求數據對應的宿主節點修改。

精確協調(Precise Reconciliation)

精確協調希望在每次通信週期內都非常準確地消除雙方的不一致性,具體表現爲相互發送對方需要更新的數據,因爲每個節點都在併發與多個節點通信,理論上精確協調很難做到。

精確協調需要給每個數據項獨立地維護自己的version,在每次交互是把所有的(key,value,version)發送到目標進行比對,從而找出雙方不同之處從而更新。但因爲Gossip消息存在大小限制,因此每次選擇發送哪些數據就成了問題。當然可以隨機選擇一部分數據,也可確定性的選擇數據。對確定性的選擇而言,可以有最老優先(根據版本)和最新優先兩種,最老優先會優先更新版本最新的數據,而最新更新正好相反,這樣會造成老數據始終得不到機會更新,也即飢餓。

當然,開發者也可根據業務場景構造自己的選擇算法,但始終都無法避免消息量過多的問題。

整體協調(Scuttlebutt Reconciliation)

整體協調與精確協調不同之處是,整體協調不是爲每個數據都維護單獨的版本號,而是爲每個節點上的宿主數據維護統一的version。

比如節點P會爲(p1,p2,…)維護一個一致的全局version,相當於把所有的宿主數據看作一個整體,當與其他節點進行比較時,只需必須這些宿主數據的最高version,如果最高version相同說明這部分數據全部一致,否則再進行精確協調。

整體協調對數據的選擇也有兩種方法:

  1. 廣度優先:根據整體version大小排序,也稱爲公平選擇
  2. 深度優先:根據包含數據多少的排序,也稱爲非公平選擇。

因爲後者更有實用價值,所以原論文更鼓勵後者

Consul中的Gossip

Consul用了兩種不同的Gossip池。我們把這兩種池分別叫做LAN池和WAN池。

LAN池

Consul中的每個數據中心有一個LAN池,它包含了這個數據中心的所有成員,包括clients和servers。LAN池用於以下幾個目的:

  1. 成員關係信息允許client自動發現server, 減少了所需要的配置量。
  2. 分佈式失敗檢測機制使得由整個集羣來做失敗檢測這件事, 而不是集中到幾臺機器上。
  3. gossip池使得類似領導人選舉這樣的事件變得可靠而且迅速。

WAN池

WAN池是全局唯一的,因爲所有的server都應該加入到WAN池中,無論它位於哪個數據中心。由WAN池提供的成員關係信息允許server做一些跨數據中心的請求。一體化的失敗檢測機制允許Consul優雅地去處理:整個數據中心失去連接, 或者僅僅是別的數據中心的某一臺失去了連接。

所有的這些特性都是利用Serf來提供的。Consul中內嵌了Serf這個lib。

參考資料

  1. http://blog.csdn.net/chen77716/article/details/6275762
  2. https://www.consul.io/docs/internals/gossip.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章