淺談分布式一致性算法raft


前言:在分布式的系統中,存在很多的節點,節點之間如何進行協作運行、高效流轉、主節點掛了怎么辦、如何選主、各節點之間如何保持一致,這都是不可不面對的問題,此時raft算法應運而生,專門 用來解決上述問題。對於分布式的一致性算法,著名的有paxos,zookeeper基於paxos提出了zab協議, paxos是出名的晦澀難懂.而raft的設計初衷就是容易理解和簡單、高效,本篇博客我們就來循序漸進的看看raft到底是什么?它的運行原理是什么樣的?

本篇博客的目錄:

一:raft的狀態

二:選主過程

三:如何保證集群一致性

四:如何處理腦裂問題

五:總結

 

一:raft的狀態

raft的集群角色分為3種,不同的節點在運行環境中處於不同的角色,任何節點的任何一個時刻都處於以下三種角色之一,不同的角色具有不同的功能,所承擔的職責也不一樣:

①:follower

follwer是集群的初始狀態,所有的節點在剛開始加入到集群中,默認是follower的角色,也就是從節點~

②:candidate

candidate的含義可以理解為候選人,這是專門用於在follower在進行選舉的時候,被投票者的稱謂,這是一個中間角色,followerA會發起投票到followerB,此時followerA的角色就是candidate

③:leader

有了從節點之后就必須有主節點了,所以接下來伴隨的是選主的過程,選主之后的節點稱之為leader,也就是主節點,主節點只有一個,由leader接收用戶的請求,每一次請求都被被記錄到log entry中

 三個角色可以這樣理解:試想新學期開學第一天,所有的同學都是普通學生的身份(follower),新學期開始需要挑選出班長(leader),需要進行投票,大家先選出幾個候選人,候選人可以自己投票給自己,此時要選中成為班長的這幾個人就是candidate,最后經過選舉出來的班長就是leader

任期:

   任期簡稱Term,是raft里面非常重要的概念,每個任期可以是任意時長,任期用連續的整數進行標號,每個節點都維護着當前的任期值,每個節點在檢測到自己的任期值低於其他節點會更新自己的任期值,設置為檢測到的較高值。當leader和candidate發現自己的任期低於別的節點,則會立即把自己轉換為follower

下面是幾種角色的流轉圖:

二:raft的選主

2.1:leader負責處理客戶端的請求

所有對日志的添加或者狀態變化的操作都是通過leader來完成,當leader接收請求之后會將日志分發到集群的所有follower節點,日志的數據流是從leader到其他的節點,而不會產生follower流向日志的情況,raft會保證流向所有follower節點的日志副本都是一致的:

選舉leader發生在以下兩種情況:

①當一個raft集群初始化的時候  ②當選舉出來的主節點宕機、崩潰的時候

2.2:接下來談一談raft是如何選主的: 

    一個 Raft集群開始,集群中的節點所有的初始狀態都是 Follower,然后設置任期(term為0),並啟動計時器發起選舉(Election),開始選舉之后每個參與方都會有一個隨機的超時時間(Election Timeout),這里的關鍵就是隨機 Timeout(150ms 到 300ms之間,最先走完timeout時間的一個節點開始發起投票,向還在 timeout 中的另外節點請求投票(Reuest Vote)並等待回復,此時它就只能投給自己,然后raft會統計得票數,在計數器時間內,得票最多的會成為leader.這樣的結果就是最先發起投票的節點會有大概率成為主節點,選出 Leader 后,term值會+1,並且Leader通過定期向所有 Follower 發送心跳信息(官方稱之為:Append Entries,Append Entries是一種RPC協議)保持連接。

   兩個節點同時發起選舉

因為follwer節點的超時時間是隨機的,所以可能會存在兩個節點正好隨機到相同的random time,並且擁有相同的term,此時raft會如何處理呢?raft會在相同的random time out時間同時發起leader選舉,因為兩個Candidate存在相同的term和timeout,並且同時發起投票,最終他們得到的votes是相同的。這個時候raft會等待下一輪的重試,下一輪兩個節點的time out可能會不同,重試直到選舉出leader

2.3:當選舉完成之后考慮以下幾個情形:

情形一:leader宕機

每次當leader對所有的followe發出Append Entries的時候,follower會有一個隨機的超時時間,如果再超時時間內收到了leader的請求就會重置超時時間,如果沒有收到超過超時時間,follower沒有收到 Leader的心跳,follower會認為 Leader 可能已經掛了,此時第一個超時的follower會發起投票,注意這個時候它依然會向宕機的原leader發出Reuest Vote,但原leader不會回復。raft設計的

請求投票都是冪等的,會檢測狀態。當收到集群超過一半的節點的RequestVote reply后,此時的follower會成為leader

 ps:后期leader恢復正常之后,加入到raft集群,初始化的角色是follower,而並非leader。因為任何時刻leader只有一個,如果是兩個,就會發生"腦裂"問題

情形二:follower宕機

   follower宕機對整個集群影響不大,最多的影響是leader發出的Append Entries無法被收到,但是leader還會繼續一直發送,直到follower恢復正常。raft會保證發送AppendEntries request的rpc消息是冪等的,如果follower已經接受到了消息,但是leader又讓它再次接受,follower會直接忽略

三:raft如何保證集群的一致性

3.1:Raft 協議由leader節點負責接收客戶端的請求,leader會將請求包裝成log entry分發到從節點,所以集群強依賴 Leader節點的可用性,以確保集群 數據的一致性。數據的流向只能從 Leader 節點向 Follower 節點轉移,這個過程叫做日志復制(Log Replication)

① 當 Client 向集群 Leader 節點 提交數據 后,Leader 節點 接收到的數據 處於 未提交狀態(Uncommitted)。

②  接着 Leader 節點會並發地向所有Follower節點復制數據並等待接收響應ACK

③ leader會等待集群中至少超過一半的節點已接收到數據后, Leader 再向 Client 確認數據 已接收。

④ 一旦向 Client 發出數據接收 Ack 響應后,表明此時 數據狀態 進入 已提交(Committed),Leader 節點再向 Follower 節點發通知告知該數據狀態已提交

⑤ follower開始commit自己的數據,此時raft集群達到主節點和從節點的一致

3.2:在進行一致性復制的過程中,假如出現了異常情況,raft都是如何處理的呢?

1.數據到達 Leader 節點前,這個階段 Leader 掛掉不影響一致性

2.數據到達 Leader 節點,但未復制到 Follower 節點。這個階段 Leader 掛掉,數據屬於 未提交狀態,Client 不會收到 Ack 會認為 超時失敗 可安全發起 重試。

3.數據到達 Leader 節點,成功復制到 Follower 所有節點,但 Follower 還未向 Leader 響應接收。這個階段 Leader 掛掉,雖然數據在 Follower 節點處於 未提交狀態(Uncommitted),但是 保持一致 的。重新選出 Leader 后可完成 數據提交。

4.數據到達 Leader 節點,成功復制到 Follower 的部分節點,但這部分 Follower 節點還未向 Leader 響應接收。這個階段 Leader 掛掉,數據在 Follower 節點處於 未提交狀態(Uncommitted)且 不一致。

Raft 協議要求投票只能投給擁有 最新數據 的節點。所以擁有最新數據的節點會被選為  Leader,然后再 強制同步數據 到其他  Follower,保證 數據不會丟失並 最終一致。
5.數據到達 Leader 節點,成功復制到 Follower 所有或多數節點,數據在 Leader 處於已提交狀態,但在 Follower 處於未提交狀態。

這個階段 Leader 掛掉,重新選出 新的 Leader 后的處理流程和階段 3 一樣。

6.數據到達 Leader 節點,成功復制到 Follower 所有或多數節點,數據在所有節點都處於已提交狀態,但還未響應 Client。這個階段 Leader 掛掉,集群內部數據其實已經是 一致的,Client 重復重試基於冪等策略對 一致性無影響。

四:如何解決腦裂問題

    當raft在集群中遇見網絡分區的時候,集群就會因此而相隔開,在不同的網絡分區里會因為無法接收到原來的leader發出的心跳而超時選主,這樣就會造成多leader現象,見下圖:在網絡分區1和網絡分區2中,出現了兩個leaderA和D,假設此時要更新分區2的值,因為分區2無法得到集群中的大多數節點的ACK,會復制失敗。而網絡分區1會成功,因為分區1中的節點更多,leaderA能得到大多數回應

當網絡恢復的時候,集群不再是雙分區,raft會有如下操作:

①: leaderD發現自己的Term小於LeaderA,會自動下台(step down)成為follower,leaderA保持不變依舊是集群中的主leader角色

②: 分區中的所有節點會回滾roll back自己的數據日志,並匹配新leader的log日志,然后實現同步提交更新自身的值。通知舊leaderA也會主動匹配主leader節點的最新值,並加入到follower中

③: 最終集群達到整體一致,集群存在唯一leader(節點A)

 五:總結

   本篇博客從整體上講了下raft的狀態角色、如何選舉出leader、如何保證一致性、以及如何處理網絡分區時的腦裂問題,整理較為粗略,raft實現起來更為復雜和細致,所以這里只是淺談一下。理解raft的主要目的在於分布式環境中,對於集群之間的節點交互、宕機后如何處理如何保證高可用、高一致性有一定的理解。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM