一致性共識算法:raft


拜占庭將軍問題是分佈式領域最複雜、最嚴格的容錯模型(可能有叛徒、信使可能被策反或者暗殺)。但在日常工作中使用的分佈式系統面對的問題不會那麼複雜,更多的是計算機故障掛掉了,或者網絡通信問題而沒法傳遞信息,這種情況不考慮計算機之間互相發送惡意信息,極大簡化了系統對容錯的要求,最主要的是達到一致性

所以將拜占庭將軍問題根據常見的工作上的問題進行簡化:假設將軍中沒有叛軍,信使的信息可靠但有可能被暗殺的情況下,將軍們如何達成一致性決定?

對於這個簡化後的問題,有許多解決方案,第一個被證明的共識算法是 Paxos,由拜占庭將軍問題的作者 Leslie Lamport 在1990年提出,最初以論文難懂而出名,後來這哥們在2001重新發了一篇簡單版的論文 Paxos Made Simple,然而還是挺難懂的。

因爲 Paxos 難懂,難實現,所以斯坦福大學的教授在2014年發表了新的分佈式協議 Raft。與 Paxos 相比,Raft 有着基本相同運行效率,但是更容易理解,也更容易被用在系統開發上

針對簡化版拜占庭將軍問題,Raft 解決方案類比

假設將軍中沒有叛軍,信使的信息可靠但有可能被暗殺的情況下,將軍們如何達成一致性決定?

Raft 的解決方案大概可以理解成 先在所有將軍中選出一個大將軍,所有的決定由大將軍來做。選舉環節:比如說現在一共有3個將軍 A, B, C,每個將軍都有一個隨機時間的倒計時器,倒計時一結束,這個將軍就會把自己當成大將軍候選人,然後派信使去問其他幾個將軍,能不能選我爲總將軍?假設現在將軍A倒計時結束了,他派信使傳遞選舉投票的信息給將軍B和C,如果將軍B和C還沒把自己當成候選人(倒計時還沒有結束),並且沒有把選舉票投給其他,他們把票投給將軍A,信使在回到將軍A時,將軍A知道自己收到了足夠的票數,成爲了大將軍。在這之後,是否要進攻就由大將軍決定,然後派信使去通知另外兩個將軍,如果在一段時間後還沒有收到回覆(可能信使被暗殺),那就再重派一個信使,直到收到回覆。

故事先講到這裏,希望不做技術方面的朋友可以大概能理解 Raft 的原理,下面從比較技術的角度講講 Raft 的原理。

1. Raft 節點狀態

從拜占庭將軍的故事映射到分佈式系統上,每個將軍相當於一個分佈式網絡節點,每個節點有三種狀態:Follower,Candidate,Leader,狀態之間是互相轉換的,可以參考下圖,具體的後面說。

image

每個節點上都有一個倒計時器 (Election Timeout),時間隨機在 150ms 到 300ms 之間。有幾種情況會重設 Timeout:

  1. 收到選舉的請求
  2. 收到 Leader 的 Heartbeat (後面會講到)

在 Raft 運行過程中,最主要進行兩個活動:

  1. 選主 Leader Election
  2. 複製日誌 Log Replication

2. 選主 Leader Election

2.1 正常情況下選主

假設現在有5個節點,5個節點一開始的狀態都是 Follower。
image

在一個節點倒計時結束 (Timeout) 後,這個節點的狀態變成 Candidate 開始選舉,它給其他幾個節點發送選舉請求 (RequestVote)

image

其他四個節點都返回成功,這個節點的狀態由 Candidate 變成了 Leader,並在每個一小段時間後,就給所有的 Follower 發送一個 Heartbeat 以保持所有節點的狀態,Follower 收到 Leader 的 Heartbeat 後重設 Timeout

這是最簡單的選主情況,只要有超過一半的節點投支持票了,Candidate 纔會被選舉爲 Leader,5個節點的情況下,3個節點 (包括 Candidate 本身) 投了支持就行。

2.2 Leader 出故障情況下的選主

一開始已經有一個 Leader,所有節點正常運行。

image
Leader 出故障掛掉了,其他四個 Follower 將進行重新選主。

image

image

image
4個節點的選主過程和5個節點的類似,在選出一個新的 Leader 後,原來的 Leader 恢復了又重新加入了,這個時候怎麼處理?在 Raft 裏,第幾輪選舉是有記錄的,重新加入的 Leader 是第一輪選舉 (Term 1) 選出來的,而現在的 Leader 則是 Term 2,所有原來的 Leader 會自覺降級爲 Follower
image

2.3 多個 Candidate 情況下的選主

假設一開始有4個節點,都還是 Follower。
image
有兩個 Follower 同時 Timeout,都變成了 Candidate 開始選舉,分別給一個 Follower 發送了投票請求。
image

兩個 Follower 分別返回了ok,這時兩個 Candidate 都只有2票,要3票才能被選成 Leader。
image

兩個 Candidate 會分別給另外一個還沒有給自己投票的 Follower 發送投票請求。
image

但是因爲 Follower 在這一輪選舉中,都已經投完票了,所以都拒絕了他們的請求。所以在 Term 2 沒有 Leader 被選出來。
image

這時,兩個節點的狀態是 Candidate,兩個是 Follower,但是他們的倒計時器仍然在運行,最先 Timeout 的那個節點會進行發起新一輪 Term 3 的投票。
image

兩個 Follower 在 Term 3 還沒投過票,所以返回 OK,這時 Candidate 一共有三票,被選爲了 Leader。
image

如果 Leader Heartbeat 的時間晚於另外一個 Candidate timeout 的時間,另外一個 Candidate 仍然會發送選舉請求。

image
兩個 Follower 已經投完票了,拒絕了這個 Candidate 的投票請求。

image
Leader 進行 Heartbeat, Candidate 收到後狀態自動轉爲 Follower,完成選主。

以上是 Raft 最重要活動之一選主的介紹,以及在不同情況下如何進行選主。

3. 複製日誌 Log Replication

3.1 正常情況下複製日誌

Raft 在實際應用場景中的一致性更多的是體現在不同節點之間的數據一致性,客戶端發送請求到任何一個節點都能收到一致的返回,當一個節點出故障後,其他節點仍然能以已有的數據正常進行。在選主之後的複製日誌就是爲了達到這個目的。

一開始,Leader 和 兩個 Follower 都沒有任何數據。

客戶端發送請求給 Leader,儲存數據 “sally”,Leader 先將數據寫在本地日誌,這時候數據還是 Uncommitted (還沒最終確認,紅色表示)

Leader 給兩個 Follower 發送 AppendEntries 請求,數據在 Follower 上沒有衝突,則將數據暫時寫在本地日誌,Follower 的數據也還是 Uncommitted。

Follower 將數據寫到本地後,返回 OK。Leader 收到後成功返回,只要收到的成功的返回數量超過半數 (包含Leader),Leader 將數據 “sally” 的狀態改成 Committed。( 這個時候 Leader 就可以返回給客戶端了)

Leader 再次給 Follower 發送 AppendEntries 請求,收到請求後,Follower 將本地日誌裏 Uncommitted 數據改成 Committed。這樣就完成了一整個複製日誌的過程,三個節點的數據是一致的,

3.2 Network Partition 情況下進行復制日誌

在 Network Partition 的情況下,部分節點之間沒辦法互相通信,Raft 也能保證在這種情況下數據的一致性。

一開始有 5 個節點處於同一網絡狀態下。

Network Partition 將節點分成兩邊,一邊有兩個節點,一邊三個節點。

兩個節點這邊已經有 Leader 了,來自客戶端的數據 “bob” 通過 Leader 同步到 Follower。

因爲只有兩個節點,少於3個節點,所以 “bob” 的狀態仍是 Uncommitted。所以在這裏,服務器會返回錯誤給客戶端

另外一個 Partition 有三個節點,進行重新選主。客戶端數據 “tom” 發到新的 Leader,通過和上節網絡狀態下相似的過程,同步到另外兩個 Follower。

因爲這個 Partition 有3個節點,超過半數,所以數據 “tom” 都 Commit 了。

網絡狀態恢復,5個節點再次處於同一個網絡狀態下。但是這裏出現了數據衝突 “bob" 和 “tom"

三個節點的 Leader 廣播 AppendEntries

兩個節點 Partition 的 Leader 自動降級爲 Follower,因爲這個 Partition 的數據 “bob” 沒有 Commit,返回給客戶端的是錯誤,客戶端知道請求沒有成功,所以 Follower 在收到 AppendEntries 請求時,可以把 “bob“ 刪除,然後同步 ”tom”,通過這麼一個過程,就完成了在 Network Partition 情況下的複製日誌,保證了數據的一致性。

小總結
Raft 是能夠實現分佈式系統強一致性的算法,每個系統節點有三種狀態 Follower,Candidate,Leader。實現 Raft 算法兩個最重要的事是:選主和複製日誌

轉自:《raft》

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