深入剖析共識性算法 Raft
安全性保證(絕對不會返回一個錯誤的結(jié)果):在非拜占庭錯誤情況下,包括網(wǎng)絡(luò)延遲、分區(qū)、丟包、冗余和亂序等錯誤都可以保證正確。 可用性:集群中只要有大多數(shù)的機(jī)器可運(yùn)行并且能夠相互通信、和客戶端通信,就可以保證可用。因此,一個典型的包含 5 個節(jié)點(diǎn)的集群可以容忍兩個節(jié)點(diǎn)的失敗。服務(wù)器被停止就認(rèn)為是失敗。他們當(dāng)有穩(wěn)定的存儲的時候可以從狀態(tài)中恢復(fù)回來并重新加入集群。 不依賴時序來保證一致性:物理時鐘錯誤或者極端的消息延遲只有在最壞情況下才會導(dǎo)致可用性問題。 通常情況下,一條指令可以盡可能快的在集群中大多數(shù)節(jié)點(diǎn)響應(yīng)一輪遠(yuǎn)程過程調(diào)用時完成。小部分比較慢的節(jié)點(diǎn)不會影響系統(tǒng)整體的性能。
分布式鎖服務(wù),比如 Zookeeper 分布式存儲系統(tǒng),比如分布式消息隊(duì)列、分布式塊系統(tǒng)、分布式文件系統(tǒng)、分布式表格系統(tǒng)等,比如大名鼎鼎的 Redis 就是基于 Raft 實(shí)現(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é)束。 如果選舉失敗,那么這個任期就會因?yàn)闆]有 Leader 而結(jié)束。
服務(wù)器節(jié)點(diǎn)可能觀察到多次的任期轉(zhuǎn)換。 服務(wù)器節(jié)點(diǎn)也可能觀察不到任何一次任期轉(zhuǎn)換。
如果一個服務(wù)器的當(dāng)前任期號比其他人小,那么他會更新自己的編號到較大的編號值。 如果一個 Candidate 或者 Leader 發(fā)現(xiàn)自己的任期號過期了,那么他會立即恢復(fù)成跟隨者狀態(tài)。 如果一個節(jié)點(diǎn)接收到一個包含過期的任期號的請求,那么他會直接拒絕這個請求。
RequestVote RPC - 請求投票 RPC,由 Candidate 在選舉期間發(fā)起。 AppendEntries RPC - 附加條目 RPC,由 Leader 發(fā)起,用來復(fù)制日志和提供一種心跳機(jī)制。
三、選舉Leader
自己成為 Leader 其他的服務(wù)器成為 Leader
沒有任何服務(wù)器成為 Leader
3.1.1自己成為 Leader
當(dāng)一個 Candidate 從整個集群半數(shù)以上的服務(wù)器節(jié)點(diǎn)獲得了針對同一個 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ā)送心跳包。
同樣的機(jī)制也被用在選票瓜分的情況下:每一個 Candidate 在開始一次選舉的時候會重置一個隨機(jī)的選舉超時時間,然后在超時時間內(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)機(jī),并向客戶端返回執(zhí)行結(jié)果。




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

存在未更新日志條目,如(a、b)。 存在未提交日志條目,如(c、d)。 或兩種情況都存在,如(e、f)。
Leader 為了使 Followers 的日志同自己的一致,Leader 需要找到 Followers 同它的日志一致的地方,然后覆蓋 Followers 在該位置之后的條目。 Leader 會從后往前試,每次日志條目失敗后嘗試前一個日志條目,直到成功找到每個 Follower 的日志一致位點(diǎn),然后向后逐條覆蓋 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é)點(diǎn)上,但是還沒有被提交。 階段 (d),S1 再次下線,S5 重新上線,并被重新選舉為 Term3 的 Leader。然后 S5 覆蓋了日志索引 2 處的日志。 階段 (e),如果階段 (d) 還未發(fā)生,即 S1 再次下線之前,S1 把自己主導(dǎo)的日志條目復(fù)制到了大多數(shù)節(jié)點(diǎn)上,那么在后續(xù) Term 里面這些新日志條目就會被提交。這樣在同一時刻就同時保證了,之前的所有舊日志條目就會被提交。
六、日志壓縮
日志元數(shù)據(jù)。最后一條已提交的日志條目的日志索引和 Term。這兩個值在快照之后的第一條日志條目的 AppendEntries RPC 的完整性檢查的時候會被用上。 系統(tǒng)當(dāng)前狀態(tài)。

七、參考資料
- END -
「技術(shù)分享」某種程度上,是讓作者和讀者,不那么孤獨(dú)的東西。歡迎關(guān)注我的微信公眾號:「Kirito的技術(shù)分享」
評論
圖片
表情
