淺談分佈式一致性算法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的主要目的在於分佈式環境中,對於集羣之間的節點交互、宕機後如何處理如何保證高可用、高一致性有一定的理解。

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