Gossip算法由於Cassandra而名聲大噪,Gossip看似簡單,但要真正弄清楚其本質遠沒看起來那麼容易。爲了尋求Gossip的本質,下面的內容主要參考Gossip的原始論文:<<Efficient Reconciliation and Flow Control for Anti-Entropy Protocols>>。git
Gossip算法如其名,靈感來自辦公室八卦,只要一我的八卦一下,在有限的時間內全部的人都會知道該八卦的信息,這種方式也與病毒傳播相似,所以Gossip有衆多的別名「閒話算法」、「疫情傳播算法」、「病毒感染算法」、「謠言傳播算法」。算法
但Gossip並非一個新東西,以前的泛洪查找、路由算法都歸屬於這個範疇,不一樣的是Gossip給這類算法提供了明確的語義、具體實施方法及收斂性證實。網絡
Gossip算法又被稱爲反熵(Anti-Entropy),熵是物理學上的一個概念,表明雜亂無章,而反熵就是在雜亂無章中尋求一致,這充分說明了Gossip的特色:在一個有界網絡中,每一個節點都隨機地與其餘節點通訊,通過一番雜亂無章的通訊,最終全部節點的狀態都會達成一致。每一個節點可能知道全部其餘節點,也可能僅知道幾個鄰居節點,只要這些節能夠經過網絡連通,最終他們的狀態都是一致的,固然這也是疫情傳播的特色。數據結構
要注意到的一點是,即便有的節點因宕機而重啓,有新節點加入,但通過一段時間後,這些節點的狀態也會與其餘節點達成一致,也就是說,Gossip自然具備分佈式容錯的優勢。併發
Gossip是一個帶冗餘的容錯算法,更進一步,Gossip是一個最終一致性算法。雖然沒法保證在某個時刻全部節點狀態一致,但能夠保證在」最終「全部節點一致,」最終「是一個現實中存在,但理論上沒法證實的時間點。負載均衡
由於Gossip不要求節點知道全部其餘節點,所以又具備去中心化的特色,節點之間徹底對等,不須要任何的中心節點。實際上Gossip能夠用於衆多能接受「最終一致性」的領域:失敗檢測、路由同步、Pub/Sub、動態負載均衡。分佈式
但Gossip的缺點也很明顯,冗餘通訊會對網路帶寬、CUP資源形成很大的負載,而這些負載又受限於通訊頻率,該頻率又影響着算法收斂的速度,後面咱們會講在各類場合下的優化方法。優化
根據原論文,兩個節點(A、B)之間存在三種通訊方式:.net
若是把兩個節點數據同步一次定義爲一個週期,則在一個週期內,push需通訊1次,pull需2次,push/pull則需3次,從效果上來說,push/pull最好,理論上一個週期內可使兩個節點徹底一致。直觀上也感受,push/pull的收斂速度是最快的。server
假設每一個節點通訊週期都能選擇(感染)一個新節點,則Gossip算法退化爲一個二分查找過程,每一個週期構成一個平衡二叉樹,收斂速度爲O(n2 ),對應的時間開銷則爲O(logn )。這也是Gossip理論上最優的收斂速度。但在實際狀況中最優收斂速度是很難達到的,假設某個節點在第i個週期被感染的機率爲pi ,第i+1個週期被感染的機率爲pi+1 ,則pull的方式:
而push爲:
顯然pull的收斂速度大於push,而每一個節點在每一個週期被感染的機率都是固定的p(0<p<1),所以Gossip算法是基於p的平方收斂,也成爲機率收斂,這在衆多的一致性算法中是很是獨特的。
個Gossip的節點的工做方式又分兩種:
Anti-Entropy模式有徹底的容錯性,但有較大的網絡、CPU負載;Rumor-Mongering模式有較小的網絡、CPU負載,但必須爲數據定義」最新「的邊界,而且難以保證徹底容錯,對失敗重啓且超過」最新「期限的節點,沒法保證最終一致性,或須要引入額外的機制處理不一致性。咱們後續着重討論Anti-Entropy模式的優化。
協調機制是討論在每次2個節點通訊時,如何交換數據能達到最快的一致性,也即消除兩個節點的不一致性。上面所講的push、pull等是通訊方式,協調是在通訊方式下的數據交換機制。協調所面臨的最大問題是,由於受限於網絡負載,不可能每次都把一個節點上的數據發送給另一個節點,也即每一個Gossip的消息大小都有上限。在有限的空間上有效率地交換全部的消息是協調要解決的主要問題。
在討論以前先聲明幾個概念:
爲了保證一致性,規定數據的value及version只有宿主節點才能修改,其餘節點只能間接經過Gossip協議來請求數據對應的宿主節點修改。
精確協調但願在每次通訊週期內都很是準確地消除雙方的不一致性,具體表現爲相互發送對方須要更新的數據,由於每一個節點都在併發與多個節點通訊,理論上精確協調很難作到。精確協調須要給每一個數據項獨立地維護本身的version,在每次交互是把全部的(key,value,version)發送到目標進行比對,從而找出雙方不一樣之處從而更新。但由於Gossip消息存在大小限制,所以每次選擇發送哪些數據就成了問題。固然能夠隨機選擇一部分數據,也可肯定性的選擇數據。對肯定性的選擇而言,能夠有最老優先(根據版本)和最新優先兩種,最老優先會優先更新版本最新的數據,而最新更新正好相反,這樣會形成老數據始終得不到機會更新,也即飢餓。
固然,開發這也可根據業務場景構造本身的選擇算法,但始終都沒法避免消息量過多的問題。
總體協調與精確協調不一樣之處是,總體協調不是爲每一個數據都維護單獨的版本號,而是爲每一個節點上的宿主數據維護統一的version。好比節點P會爲(p1,p2,...)維護一個一致的全局version,至關於把全部的宿主數據看做一個總體,當與其餘節點進行比較時,只需必須這些宿主數據的最高version,若是最高version相同說明這部分數據所有一致,不然再進行精確協調。
總體協調對數據的選擇也有兩種方法:
通過驗證,Cassandra實現了基於總體協調的push/push模式,有幾個組件:
三條消息分別對應push/pull的三個階段:
還有三種狀態:
Cassandra主要是使用Gossip完成三方面的功能:
Gossip是一種去中心化、容錯而又最終一致性的絕妙算法,其收斂性不但獲得證實還具備指數級的收斂速度。使用Gossip的系統能夠很容易的把Server擴展到更多的節點,知足彈性擴展垂手可得。
惟一的缺點是收斂是最終一致性,不使用那些強一致性的場景,好比2pc。