深入剖析共識性算法 Raft
作者:vivo?互聯(lián)網(wǎng)服務(wù)器團隊-ZhangPeng
安全性保證(絕對不會返回一個錯誤的結(jié)果):在非拜占庭錯誤情況下,包括網(wǎng)絡(luò)延遲、分區(qū)、丟包、冗余和亂序等錯誤都可以保證正確。 可用性:集群中只要有大多數(shù)的機器可運行并且能夠相互通信、和客戶端通信,就可以保證可用。因此,一個典型的包含 5 個節(jié)點的集群可以容忍兩個節(jié)點的失敗。服務(wù)器被停止就認(rèn)為是失敗。他們當(dāng)有穩(wěn)定的存儲的時候可以從狀態(tài)中恢復(fù)回來并重新加入集群。 不依賴時序來保證一致性:物理時鐘錯誤或者極端的消息延遲只有在最壞情況下才會導(dǎo)致可用性問題。 通常情況下,一條指令可以盡可能快的在集群中大多數(shù)節(jié)點響應(yīng)一輪遠程過程調(diào)用時完成。小部分比較慢的節(jié)點不會影響系統(tǒng)整體的性能。
分布式鎖服務(wù),比如 Zookeeper 分布式存儲系統(tǒng),比如分布式消息隊列、分布式塊系統(tǒng)、分布式文件系統(tǒng)、分布式表格系統(tǒng)等,比如大名鼎鼎的 Redis 就是基于 Raft 實現(xiàn)分布式一致性 高可靠元信息管理,比如各類 Master 模塊的 HA
二、 Raft基礎(chǔ)
Leader - 領(lǐng)導(dǎo)者,通常一個系統(tǒng)中是一主(Leader)多從(Follower)。Leader 負(fù)責(zé)處理所有的客戶端請求。 Follower - 跟隨者,不會發(fā)送任何請求,只是簡單的?響應(yīng)來自 Leader 或者 Candidate 的請求。 Candidate - 參選者,選舉新 Leader 時的臨時角色。

Follower 只響應(yīng)來自其他服務(wù)器的請求。在一定時限內(nèi),如果 Follower 接收不到消息,就會轉(zhuǎn)變成 Candidate,并發(fā)起選舉。 Candidate 向 Follower 發(fā)起投票請求,如果獲得集群中半數(shù)以上的選票,就會轉(zhuǎn)變?yōu)?Leader。 在一個 Term 內(nèi),Leader 始終保持不變,直到下線了。Leader 需要周期性向所有 Follower 發(fā)送心跳消息,以阻止 Follower 轉(zhuǎn)變?yōu)?Candidate。

如果選舉成功,Leader 會管理整個集群直到任期結(jié)束。 如果選舉失敗,那么這個任期就會因為沒有 Leader 而結(jié)束。
服務(wù)器節(jié)點可能觀察到多次的任期轉(zhuǎn)換。 服務(wù)器節(jié)點也可能觀察不到任何一次任期轉(zhuǎn)換。
如果一個服務(wù)器的當(dāng)前任期號比其他人小,那么他會更新自己的編號到較大的編號值。 如果一個 Candidate 或者 Leader 發(fā)現(xiàn)自己的任期號過期了,那么他會立即恢復(fù)成跟隨者狀態(tài)。 如果一個節(jié)點接收到一個包含過期的任期號的請求,那么他會直接拒絕這個請求。
RequestVote RPC - 請求投票 RPC,由 Candidate 在選舉期間發(fā)起。 AppendEntries RPC - 附加條目 RPC,由 Leader 發(fā)起,用來復(fù)制日志和提供一種心跳機制。
三、選舉Leader
自己成為 Leader 其他的服務(wù)器成為 Leader
沒有任何服務(wù)器成為 Leader
3.1.1自己成為 Leader
當(dāng)一個 Candidate 從整個集群半數(shù)以上的服務(wù)器節(jié)點獲得了針對同一個 Term 的選票,那么它就贏得了這次選舉并成為 Leader。每個服務(wù)器最多會對一個 Term 投出一張選票,按照先來先服務(wù)(FIFO)的原則。要求半數(shù)以上選票的規(guī)則確保了最多只會有一個 Candidate 贏得此次選舉。 一旦 Candidate 贏得選舉,就立即成為 Leader。然后它會向其他的服務(wù)器發(fā)送心跳消息來建立自己的權(quán)威并且阻止新的領(lǐng)導(dǎo)人的產(chǎn)生。
3.1.2 其他的服務(wù)器成為 Leader
如果這個 Leader 的 Term 號(包含在此次的 RPC 中)不小于 Candidate 當(dāng)前的 Term,那么 Candidate 會承認(rèn) Leader 合法并回到 Follower 狀態(tài)。 如果此次 RPC 中的 Term 號比自己小,那么 Candidate 就會拒絕這個消息并繼續(xù)保持 Candidate 狀態(tài)。
3.1.3 沒有任何服務(wù)器成為 Leader
以至于在大多數(shù)情況下,只有一個服務(wù)器會超時,然后它贏得選舉,成為 Leader,并在其他服務(wù)器超時之前發(fā)送心跳包。
同樣的機制也被用在選票瓜分的情況下:每一個 Candidate 在開始一次選舉的時候會重置一個隨機的選舉超時時間,然后在超時時間內(nèi)等待投票的結(jié)果;這樣減少了在新的選舉中另外的選票瓜分的可能性。
3.2?單Candidate選舉




3.3?多 Candidate 選舉


四、日志復(fù)制
日志條目中的 Term 號被用來檢查是否出現(xiàn)不一致的情況。 日志條目中的日志索引(一個整數(shù)值)用來表明它在日志中的位置。

這個特性基于這條原則:Leader 最多在一個 Term 內(nèi)、在指定的一個日志索引上創(chuàng)建一條日志條目,同時日志條目在日志中的位置也從來不會改變。
如果不同日志中的兩個日志條目有著相同的日志索引和 Term,則它們之前的所有條目都是完全一樣的。
這個特性由 AppendEntries RPC 的一個簡單的一致性檢查所保證。在發(fā)送 AppendEntries RPC 時,Leader 會把新日志條目之前的日志條目的日志索引和 Term 號一起發(fā)送。如果 Follower 在它的日志中找不到包含相同日志索引和 Term 號的日志條目,它就會拒絕接收新的日志條目。

Leader 負(fù)責(zé)處理所有客戶端的請求。 Leader 把請求作為日志條目加入到它的日志中,然后并行的向其他服務(wù)器發(fā)送 AppendEntries RPC 請求,要求 Follower 復(fù)制日志條目。 Follower 復(fù)制成功后,返回確認(rèn)消息。 當(dāng)這個日志條目被半數(shù)以上的服務(wù)器復(fù)制后,Leader 提交這個日志條目到它的復(fù)制狀態(tài)機,并向客戶端返回執(zhí)行結(jié)果。




4.3.1 Leader 和 Follower 日志不一致的可能

存在未更新日志條目,如(a、b)。 存在未提交日志條目,如(c、d)。 或兩種情況都存在,如(e、f)。
Leader 為了使 Followers 的日志同自己的一致,Leader 需要找到 Followers 同它的日志一致的地方,然后覆蓋 Followers 在該位置之后的條目。 Leader 會從后往前試,每次日志條目失敗后嘗試前一個日志條目,直到成功找到每個 Follower 的日志一致位點,然后向后逐條覆蓋 Followers 在該位置之后的條目。
五、安全性
先判斷 Term,哪個數(shù)值大即代表哪個日志比較新。 如果 Term 相同,再比較 日志索引,哪個數(shù)值大即代表哪個日志比較新。

階段 (a)?,S1 是 Leader,且 S1 寫入日志條目為 (Term 2,日志索引 2),只有 S2 復(fù)制了這個日志條目。 階段 (b),S1 下線,S5 被選舉為 Term3 的 Leader。S5 寫入日志條目為 (Term 3,日志索引 2)。 階段 (c),S5 下線,S1 重新上線,并被選舉為 Term4 的 Leader。此時,Term 2 的那條日志條目已經(jīng)被復(fù)制到了集群中的大多數(shù)節(jié)點上,但是還沒有被提交。 階段 (d),S1 再次下線,S5 重新上線,并被重新選舉為 Term3 的 Leader。然后 S5 覆蓋了日志索引 2 處的日志。 階段 (e),如果階段 (d) 還未發(fā)生,即 S1 再次下線之前,S1 把自己主導(dǎo)的日志條目復(fù)制到了大多數(shù)節(jié)點上,那么在后續(xù) Term 里面這些新日志條目就會被提交。這樣在同一時刻就同時保證了,之前的所有舊日志條目就會被提交。
六、日志壓縮
日志元數(shù)據(jù)。最后一條已提交的日志條目的日志索引和 Term。這兩個值在快照之后的第一條日志條目的 AppendEntries RPC 的完整性檢查的時候會被用上。 系統(tǒng)當(dāng)前狀態(tài)。

七、參考資料
評論
圖片
表情
