Raft
也是一個 一致性算法,和 Paxos
目標相同。但它還有另外一個名字 - 易於理解的一致性算法。Paxos
和 Raft
都是爲了實現 一致性 產生的。這個過程如同選舉同樣,參選者 須要說服 大多數選民 (服務器) 投票給他,一旦選定後就跟隨其操做。Paxos
和 Raft
的區別在於選舉的 具體過程 不一樣。git
在進入正題前,給你們分享一個《數學發散思惟》中的一個故事,站在不一樣思惟角度上,瞭解對一個問題理解的差別性。github
問題: 甲乙兩人輪流在一張圓桌上平放黑白圍棋子,每次放一子,棋子不準重疊,誰先沒有地方放就輸。請問怎樣放才能贏?算法
這個問題有兩層意思,第一,有沒有一種放法保證必贏?第二,若是有怎麼證實?編程
上圖回答了這個問題,那就是先行者必勝,這裏使用了三種不一樣的思惟方式來闡述:後端
假如桌子只有一個圍棋子那麼大。緩存
假如桌子無限大,先行者先佔住圓心。因爲圓是對稱圖形,因此只要對手還能找到位置放,你總能在對稱的另外一面找到位置放。安全
一個圓中可畫單數個直徑相等且互切的小圓。服務器
三種不一樣的思惟方式在可理解性難度上逐漸加深。網絡
第一種是 極簡化思惟,但數學上是 不嚴謹 的。多線程
第二種是 極限思惟,和第一種結合起來就是 數學概括法,在數學上是 嚴謹 的。
第三種是 形象思惟,使用了 幾何學概念,但對於沒有幾何學基礎知識的人就很難理解了。
Raft
協議將 Server
進程分紅三類,分別是 Leader
,Candidate
,Follower
。一個 Server
進程在某一時刻,只能是其中 一種類型,但這不是固定的。不一樣的時刻,它可能擁有不一樣的類型,一個 Server
進程的類型是如何改變的,後面會有解釋。
在一個由 Raft
協議組織的集羣中有三類角色:
就像一個民主社會,領袖由民衆投票選出。剛開始沒有 領袖,全部集羣中的 參與者 都是 羣衆,那麼首先開啓一輪大選。在大選期間 全部羣衆 都能參與競選,這時全部羣衆的角色就變成了 候選人,民主投票選出領袖後就開始了這屆領袖的任期,而後選舉結束,全部除 領袖 的 候選人 又變回 羣衆角色 服從領袖領導。
這裏提到一個概念 「任期」,用術語 Term
表達。關於 Raft
協議的核心概念和術語就這麼多,並且和現實民主制度很是匹配,因此很容易理解。
三類角色的變遷圖以下,結合後面的選舉過程來看很容易理解。
在極簡的思惟下,一個最小的 Raft
民主集羣須要 三個參與者(以下圖:A
、B
、C
),這樣纔可能投出多數票。
初始狀態 ABC
都是 Follower
,而後發起選舉這時有 三種 可能的情形發生。下圖中前二種都能選出 Leader
,第三種則代表 本輪投票無效(Split Votes
)。對於第三種,每方都投給了本身,結果沒有任何一方得到多數票。以後 每一個參與方 隨機休息一陣(Election Timeout
)從新發起投票直到一方得到多數票。這裏的關鍵就是隨機 timeout
,最早從 timeout
中恢復發起投票的一方,向還在 timeout
中的另外兩方 請求投票,這時它就只能投給本身,致使很快達成一致。
選出 Leader
後,Leader
經過 按期 向全部 Follower
發送 心跳信息 維持其統治。若 Follower
一段時間未收到 Leader
的 心跳,則認爲 Leader
可能已經掛了,而後再次發起 選舉 過程。
Raft
協議 強依賴 Leader
節點的 可用性,以確保集羣 數據的一致性。數據的流向 只能從 Leader
節點向 Follower
節點轉移。具體過程以下:
當 Client
向集羣 Leader
節點 提交數據 後,Leader
節點 接收到的數據 處於 未提交狀態(Uncommitted
)。
接着 Leader
節點會 併發地 向全部 Follower
節點 複製數據 並 等待接收響應。
集羣中至少 超過半數 的節點 已接收 到數據後, Leader
再向 Client
確認數據 已接收。
一旦向 Client
發出數據接收 Ack
響應後,代表此時 數據狀態 進入 已提交(Committed
),Leader
節點再向 Follower
節點發通知告知該 數據狀態已提交。
在這個過程當中,主節點 可能在 任意階段 掛掉,看下 Raft
協議如何針對不一樣階段保障 數據一致性 的。
數據到達 Leader 節點前,這個階段 Leader 掛掉不影響一致性,不用多說。
數據到達 Leader 節點,但未複製到 Follower 節點。
這個階段 Leader
掛掉,數據屬於 未提交狀態,Client
不會收到 Ack
會認爲 超時失敗 可安全發起 重試。
Follower
節點上沒有該數據,從新選主 後 Client
重試 從新提交 可成功。原來的 Leader
節點 恢復 後做爲 Follower
加入集羣,從新從 當前任期 的新 Leader
處 同步數據,強制保持和 Leader
數據一致。
數據到達 Leader 節點,成功複製到 Follower 全部節點,但 Follower 還未向 Leader 響應接收。
這個階段 Leader
掛掉,雖然數據在 Follower
節點處於 未提交狀態(Uncommitted
),可是 保持一致 的。從新選出 Leader
後可完成 數據提交。
此時 Client
因爲不知到底提交成功沒有,可重試提交。針對這種狀況 Raft
要求 RPC
請求實現 冪等性,也就是要實現 內部去重機制。
數據到達 Leader 節點,成功複製到 Follower 的部分節點,但這部分 Follower 節點還未向 Leader 響應接收。
這個階段 Leader
掛掉,數據在 Follower
節點處於 未提交狀態(Uncommitted
)且 不一致。
Raft
協議要求投票只能投給擁有 最新數據 的節點。因此擁有最新數據的節點會被選爲 Leader
,而後再 強制同步數據 到其餘 Follower
,保證 數據不會丟失並 最終一致。
數據到達 Leader 節點,成功複製到 Follower 全部或多數節點,數據在 Leader 處於已提交狀態,但在 Follower 處於未提交狀態。
這個階段 Leader
掛掉,從新選出 新的 Leader
後的處理流程和階段 3
同樣。
數據到達 Leader 節點,成功複製到 Follower 全部或多數節點,數據在全部節點都處於已提交狀態,但還未響應 Client。
這個階段 Leader
掛掉,集羣內部數據其實已是 一致的,Client
重複重試基於冪等策略對 一致性無影響。
網絡分區致使的腦裂狀況,出現雙 Leader 的現象。
網絡分區 將原先的 Leader
節點和 Follower
節點分隔開,Follower
收不到 Leader
的 心跳 將 從新 發起選舉產生新的 Leader
,這時就產生了 雙Leader 現象。
原先的 Leader
獨自在一個區,向它提交數據不可能複製到多數節點因此永遠提交不成功。向新的 Leader
提交數據能夠提交成功。
網絡恢復 後,舊的 Leader
發現集羣中有 更新任期(Term
)的新 Leader
,則 自動降級 爲 Follower
並重新 Leader
處 同步數據 達成集羣 數據一致。
綜上窮舉分析了 最小集羣(3
節點)面臨的全部狀況,能夠看出 Raft
協議都能很好的應對 一致性問題,而且很容易理解。
Paxos
算法是 Leslie Lamport
在 1990
年就公開發表在了本身的網站上,想一想咱們是何時才據說的?何時纔有一個可用的實現?而 Raft
算法是 2013
年發表的,你們在參考 Raft開源實現庫,能夠看到有不少基於不一樣語言的 開源實現庫,這就是 可理解性 的重要性。
歡迎關注公衆號: 零壹技術棧
本賬號將持續分享後端技術乾貨,包括虛擬機基礎,多線程編程,高性能框架,異步、緩存和消息中間件,分佈式和微服務,架構學習和進階等學習資料和文章。