consul原理學習

前邊兩篇分別說了consul集羣的安裝以及服務註冊,測試環境使用consul的架構。這篇文章主要是記錄學習consul原理的過程,有什麼不對請各位指出,下邊這個圖是從官網是扒下來的。

可以看到consul可以有多個數據中心,多個數據中心構成consul集羣,每個數據中心內,包含3個或5個(官方推薦)的consul sever,這樣可以以較快的速度達成共識,以及可以高達上千個的consul client,每個數據中心有個一leader,所有數據中心的server組成的集羣可以選舉出一個leader,因爲每個數據中心的節點是一個raft集合。從上邊這個圖中可以看到,consul client通過rpc的方式將請求轉發到consul server ,consul server 再將請求轉發到 server leader,server leader處理所有的請求,並將信息同步到其他的server中去。當一個數據中心的server沒有leader的時候,這時候請求會被轉發到其他的數據中心的consul server上,然後再轉發到本數據中心的server leader上。

關於一些關鍵詞,以下來自http://www.cnblogs.com/shanyou/p/6286207.html

  • Agent——agent是一直運行在Consul集羣中每個成員上的守護進程。通過運行 consul agent 來啓動。agent可以運行在client或者server模式。指定節點作爲client或者server是非常簡單的,除非有其他agent實例。所有的agent都能運行DNS或者HTTP接口,並負責運行時檢查和保持服務同步。
  • Client——一個Client是一個轉發所有RPC到server的代理。這個client是相對無狀態的。client唯一執行的後臺活動是加入LAN gossip池。這有一個最低的資源開銷並且僅消耗少量的網絡帶寬。
  • Server——一個server是一個有一組擴展功能的代理,這些功能包括參與Raft選舉,維護集羣狀態,響應RPC查詢,與其他數據中心交互WAN gossip和轉發查詢給leader或者遠程數據中心。
  • DataCenter——雖然數據中心的定義是顯而易見的,但是有一些細微的細節必須考慮。例如,在EC2中,多個可用區域被認爲組成一個數據中心?我們定義數據中心爲一個私有的,低延遲和高帶寬的一個網絡環境。這不包括訪問公共網絡,但是對於我們而言,同一個EC2中的多個可用區域可以被認爲是一個數據中心的一部分。
  • Consensus——在我們的文檔中,我們使用Consensus來表明就leader選舉和事務的順序達成一致。由於這些事務都被應用到有限狀態機上,Consensus暗示複製狀態機的一致性。
  • Gossip——Consul建立在Serf的基礎之上,它提供了一個用於多播目的的完整的gossip協議。Serf提供成員關係,故障檢測和事件廣播。更多的信息在gossip文檔中描述。這足以知道gossip使用基於UDP的隨機的點到點通信。
  • LAN Gossip——它包含所有位於同一個局域網或者數據中心的所有節點。
  • WAN Gossip——它只包含Server。這些server主要分佈在不同的數據中心並且通常通過因特網或者廣域網通信。
  • RPC——遠程過程調用。這是一個允許client請求server的請求/響應機制。

關於Gossip協議以下來自http://blog.csdn.net/chen77716/article/details/6275762

Gossip算法因爲Cassandra而名聲大噪,Gossip看似簡單,但要真正弄清楚其本質遠沒看起來那麼容易。爲了尋求Gossip的本質,下面的內容主要參考Gossip的原始論文:<<Efficient Reconciliation and Flow Control for Anti-Entropy Protocols>>。

 

1. Gossip背景

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

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

2. Gossip特點

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

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

3. Gossip本質

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

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

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

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

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

  • push: A節點將數據(key,value,version)及對應的版本號推送給B節點,B節點更新A中比自己新的數據
  • pull:A僅將數據key,version推送給B,B將本地比A新的數據(Key,value,version)推送給A,A更新本地
  • 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的方式:

pull

而push爲:

push

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

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

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

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

5. Anti-Entropy的協調機制

協調機制是討論在每次2個節點通信時,如何交換數據能達到最快的一致性,也即消除兩個節點的不一致性。上面所講的push、pull等是通信方式,協調是在通信方式下的數據交換機制。協調所面臨的最大問題是,因爲受限於網絡負載,不可能每次都把一個節點上的數據發送給另外一個節點,也即每個Gossip的消息大小都有上限。在有限的空間上有效率地交換所有的消息是協調要解決的主要問題。

在討論之前先聲明幾個概念:

  • 令N = {p,q,s,...}爲需要gossip通信的server集合,有界大小
  • 令(p1,p2,...)是宿主在節點p上的數據,其中數據有(key,value,version)構成,q的規則與p類似。

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

5.1 精確協調(Precise Reconciliation)

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

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

5.2 整體協調(Scuttlebutt Reconciliation)

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

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

  • 廣度優先:根據整體version大小排序,也稱爲公平選擇
  • 深度優先:根據包含數據多少的排序,也稱爲非公平選擇。因爲後者更有實用價值,所以原論文更鼓勵後者

6. Cassandra中的實現

經過驗證,Cassandra實現了基於整體協調的push/push模式,有幾個組件:

三條消息分別對應push/pull的三個階段:

  • GossipDigitsMessage
  • GossipDigitsAckMessage
  • GossipDigitsAck2Message

還有三種狀態:

  • EndpointState:維護宿主數據的全局version,並封裝了HeartBeat和ApplicationState
  • HeartBeat:心跳信息
  • ApplicationState:系統負載信息(磁盤使用率)

Cassandra主要是使用Gossip完成三方面的功能:

  • 失敗檢測
  • 動態負載均衡
  • 去中心化的彈性擴展

7. 總結

Gossip是一種去中心化、容錯而又最終一致性的絕妙算法,其收斂性不但得到證明還具有指數級的收斂速度。使用Gossip的系統可以很容易的把Server擴展到更多的節點,滿足彈性擴展輕而易舉。

唯一的缺點是收斂是最終一致性,不使用那些強一致性的場景,比如2pc。


關於raft協議,以下來自http://www.jdon.com/artichect/raft.html

過去, Paxos一直是分佈式協議的標準,但是Paxos難於理解,更難以實現,Google的分佈式鎖系統Chubby作爲Paxos實現曾經遭遇到很多坑。

  來自Stanford的新的分佈式協議研究稱爲Raft,它是一個爲真實世界應用建立的協議,主要注重協議的落地性和可理解性。

  在瞭解Raft之前,我們先了解Consensus一致性這個概念,它是指多個服務器在狀態達成一致,但是在一個分佈式系統中,因爲各種意外可能,有的服務器可能會崩潰或變得不可靠,它就不能和其他服務器達成一致狀態。這樣就需要一種Consensus協議,一致性協議是爲了確保容錯性,也就是即使系統中有一兩個服務器當機,也不會影響其處理過程。

  爲了以容錯方式達成一致,我們不可能要求所有服務器100%都達成一致狀態,只要超過半數的大多數服務器達成一致就可以了,假設有N臺服務器,N/2 +1 就超過半數,代表大多數了。

  Paxos和Raft都是爲了實現Consensus一致性這個目標,這個過程如同選舉一樣,參選者需要說服大多數選民(服務器)投票給他,一旦選定後就跟隨其操作。Paxos和Raft的區別在於選舉的具體過程不同。

  在Raft中,任何時候一個服務器可以扮演下面角色之一:

  1. Leader: 處理所有客戶端交互,日誌複製等,一般一次只有一個Leader.
  2. Follower: 類似選民,完全被動
  3. Candidate候選人: 類似Proposer律師,可以被選爲一個新的領導人。

Raft階段分爲兩個,首先是選舉過程,然後在選舉出來的領導人帶領進行正常操作,比如日誌複製等。下面用圖示展示這個過程:

1. 任何一個服務器都可以成爲一個候選者Candidate,它向其他服務器Follower發出要求選舉自己的請求:

2. 其他服務器同意了,發出OK。

注意如果在這個過程中,有一個Follower當機,沒有收到請求選舉的要求,因此候選者可以自己選自己,只要達到N/2 + 1 的大多數票,候選人還是可以成爲Leader的。

3. 這樣這個候選者就成爲了Leader領導人,它可以向選民也就是Follower們發出指令,比如進行日誌複製。

4. 以後通過心跳進行日誌複製的通知

5. 如果一旦這個Leader當機崩潰了,那麼Follower中有一個成爲候選者,發出邀票選舉。

6. Follower同意後,其成爲Leader,繼續承擔日誌複製等指導工作:

 

值得注意的是,整個選舉過程是有一個時間限制的,如下圖:

  Splite Vote是因爲如果同時有兩個候選人向大家邀票,這時通過類似加時賽來解決,兩個候選者在一段timeout比如300ms互相不服氣的等待以後,因爲雙方得到的票數是一樣的,一半對一半,那麼在300ms以後,再由這兩個候選者發出邀票,這時同時的概率大大降低,那麼首先發出邀票的的候選者得到了大多數同意,成爲領導者Leader,而另外一個候選者後來發出邀票時,那些Follower選民已經投票給第一個候選者,不能再投票給它,它就成爲落選者了,最後這個落選者也成爲普通Follower一員了。

 

日誌複製

  下面以日誌複製爲例子說明Raft算法,假設Leader領導人已經選出,這時客戶端發出增加一個日誌的要求,比如日誌是"sally":

2. Leader要求Followe遵從他的指令,都將這個新的日誌內容追加到他們各自日誌中:

3.大多數follower服務器將日誌寫入磁盤文件後,確認追加成功,發出Commited Ok:

4. 在下一個心跳heartbeat中,Leader會通知所有Follwer更新commited 項目。

對於每個新的日誌記錄,重複上述過程。

如果在這一過程中,發生了網絡分區或者網絡通信故障,使得Leader不能訪問大多數Follwers了,那麼Leader只能正常更新它能訪問的那些Follower服務器,而大多數的服務器Follower因爲沒有了Leader,他們重新選舉一個候選者作爲Leader,然後這個Leader作爲代表於外界打交道,如果外界要求其添加新的日誌,這個新的Leader就按上述步驟通知大多數Followers,如果這時網絡故障修復了,那麼原先的Leader就變成Follower,在失聯階段這個老Leader的任何更新都不能算commit,都回滾,接受新的Leader的新的更新。

總結:目前幾乎所有語言都已經有支持Raft算法的庫包,具體可參考:raftconsensus.github.io

英文動畫演示Raft

CAP定理

分佈式Paxos算法

ZooKeeper在服務發現中應用

Raft英文動畫演示的文字

So What is Distributed Consensus?

Let's start with an example...

Let's say we have a single node system
For this example, you can think of our node as a database server that stores a single value.
We also have a client that can send a value to the server.
Coming to agreement, or consensus, on that value is easy with one node.
But how do we come to consensus if we have multiple nodes?
That's the problem of distributed consensus.
Raft is a protocol for implementing distributed consensus.
Let's look at a high level overview of how it works.
A node can be in 1 of 3 states:The Follower state,the Candidate state,or the Leader state.
All our nodes start in the follower state.
If followers don't hear from a leader then they can become a candidate.
The candidate then requests votes from other nodes.
Nodes will reply with their vote.
The candidate becomes the leader if it gets votes from a majority of nodes.
This process is called Leader Election.
All changes to the system now go through the leader.
Each change is added as an entry in the node's log.
This log entry is currently uncommitted so it won't update the node's value.
To commit the entry the node first replicates it to the follower nodes...
then the leader waits until a majority of nodes have written the entry.
The entry is now committed on the leader node and the node state is "5".
The leader then notifies the followers that the entry is committed.
The cluster has now come to consensus about the system state.
This process is called Log Replication.

Leader Election
In Raft there are two timeout settings which control elections.
First is the election timeout.
The election timeout is the amount of time a follower waits until becoming a candidate.
The election timeout is randomized to be between 150ms and 300ms.
After the election timeout the follower becomes a candidate and starts a new election term......votes for itself......and sends out Request Vote messages to other nodes.
If the receiving node hasn't voted yet in this term then it votes for the candidate.....and the node resets its election timeout.
Once a candidate has a majority of votes it becomes leader.
The leader begins sending out Append Entries messages to its followers.
These messages are sent in intervals specified by the heartbeat timeout.
Followers then respond to each Append Entries message.
This election term will continue until a follower stops receiving heartbeats and becomes a candidate.
Let's stop the leader and watch a re-election happen.
Node B is now leader of term 2.
Requiring a majority of votes guarantees that only one leader can be elected per term.
If two nodes become candidates at the same time then a split vote can occur.
Let's take a look at a split vote example...
Two nodes both start an election for the same term......and each reaches a single follower node before the other.
Now each candidate has 2 votes and can receive no more for this term.
The nodes will wait for a new election and try again.
Node D received a majority of votes in term 5 so it becomes leader.

Log Replication
Term: 1
Node BTerm: 1Leader: A
Node CTerm: 1Leader: A
Once we have a leader elected we need to replicate all changes to our system to all nodes.
This is done by using the same Append Entries message that was used for heartbeats.
Let's walk through the process.
First a client sends a change to the leader.
The change is appended to the leader's log......then the change is sent to the followers on the next heartbeat.
An entry is committed once a majority of followers acknowledge it.....and a response is sent to the client.
Now let's send a command to increment the value by "2".
Our system value is now updated to "7".
Raft can even stay consistent in the face of network partitions.
Let's add a partition to separate A & B from C, D & E.
Because of our partition we now have two leaders in different terms.
Let's add another client and try to update both leaders.
One client will try to set the value of node B to "3".
Node B cannot replicate to a majority so its log entry stays uncommitted.
The other client will try to set the value of node C to "8".
This will succeed because it can replicate to a majority.
Now let's heal the network partition.
Node B will see the higher election term and step down.
Both nodes A & B will roll back their uncommitted entries and match the new leader's log.
Our log is now consistent across our cluster.


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