Raft 協(xié)議的易理解性描述
雖然 Raft 的論文比 Paxos 簡單版論文還容易讀了,但論文依然發(fā)散的比較多谤草,相對冗長膨俐。讀完后掩卷沉思覺得還是整理一下才會更牢靠沙郭,變成真正屬于自己的榴芳。這里我就借助前面黑白棋落子里第一種極簡思維來描述和概念驗證下 Raft 協(xié)議的工作方式嗡靡。
在一個由 Raft 協(xié)議組織的集群中有三類角色:
Leader(領(lǐng)袖)
Follower(群眾)
Candidate(候選人)
就像一個民主社會,領(lǐng)袖由民眾投票選出窟感。剛開始沒有領(lǐng)袖讨彼,所有集群中的參與者都是群眾,那么首先開啟一輪大選柿祈,在大選期間所有群眾都能參與競選哈误,這時所有群眾的角色就變成了候選人,民主投票選出領(lǐng)袖后就開始了這屆領(lǐng)袖的任期躏嚎,然后選舉結(jié)束蜜自,所有除領(lǐng)袖的候選人又變回群眾角色服從領(lǐng)袖領(lǐng)導。這里提到一個概念「任期」卢佣,用術(shù)語 Term 表達重荠。關(guān)于 Raft 協(xié)議的核心概念和術(shù)語就這么多而且和現(xiàn)實民主制度非常匹配,所以很容易理解珠漂。三類角色的變遷圖如下晚缩,結(jié)合后面的選舉過程來看很容易理解尾膊。
Leader 選舉過程
在極簡的思維下媳危,一個最小的 Raft 民主集群需要三個參與者(如下圖:A、B冈敛、C)待笑,這樣才可能投出多數(shù)票。初始狀態(tài) ABC 都是 Follower抓谴,然后發(fā)起選舉這時有三種可能情形發(fā)生暮蹂。下圖中前二種都能選出 Leader,第三種則表明本輪投票無效(Split Votes)癌压,每方都投給了自己仰泻,結(jié)果沒有任何一方獲得多數(shù)票。之后每個參與方隨機休息一陣(Election Timeout)重新發(fā)起投票直到一方獲得多數(shù)票滩届。這里的關(guān)鍵就是隨機 timeout集侯,最先從 timeout 中恢復發(fā)起投票的一方向還在 timeout 中的另外兩方請求投票,這時它們就只能投給對方了,很快達成一致棠枉。
選出 Leader 后浓体,Leader 通過定期向所有 Follower 發(fā)送心跳信息維持其統(tǒng)治。若 Follower 一段時間未收到 Leader 的心跳則認為 Leader 可能已經(jīng)掛了再次發(fā)起選主過程辈讶。
Leader 節(jié)點對一致性的影響
Raft 協(xié)議強依賴 Leader 節(jié)點的可用性來確保集群數(shù)據(jù)的一致性命浴。數(shù)據(jù)的流向只能從 Leader 節(jié)點向 Follower 節(jié)點轉(zhuǎn)移。當 Client 向集群 Leader 節(jié)點提交數(shù)據(jù)后贱除,Leader 節(jié)點接收到的數(shù)據(jù)處于未提交狀態(tài)(Uncommitted)生闲,接著 Leader 節(jié)點會并發(fā)向所有 Follower 節(jié)點復制數(shù)據(jù)并等待接收響應,確保至少集群中超過半數(shù)節(jié)點已接收到數(shù)據(jù)后再向 Client 確認數(shù)據(jù)已接收勘伺。一旦向 Client 發(fā)出數(shù)據(jù)接收 Ack 響應后跪腹,表明此時數(shù)據(jù)狀態(tài)進入已提交(Committed),Leader 節(jié)點再向 Follower 節(jié)點發(fā)通知告知該數(shù)據(jù)狀態(tài)已提交飞醉。
在這個過程中冲茸,主節(jié)點可能在任意階段掛掉,看下 Raft 協(xié)議如何針對不同階段保障數(shù)據(jù)一致性的缅帘。
1. 數(shù)據(jù)到達 Leader 節(jié)點前
這個階段 Leader 掛掉不影響一致性轴术,不多說。
2. 數(shù)據(jù)到達 Leader 節(jié)點钦无,但未復制到 Follower 節(jié)點
這個階段 Leader 掛掉逗栽,數(shù)據(jù)屬于未提交狀態(tài),Client 不會收到 Ack 會認為超時失敗可安全發(fā)起重試失暂。Follower 節(jié)點上沒有該數(shù)據(jù)彼宠,重新選主后 Client 重試重新提交可成功。原來的 Leader 節(jié)點恢復后作為 Follower 加入集群重新從當前任期的新 Leader 處同步數(shù)據(jù)弟塞,強制保持和 Leader 數(shù)據(jù)一致凭峡。
3. 數(shù)據(jù)到達 Leader 節(jié)點,成功復制到 Follower 所有節(jié)點决记,但還未向 Leader 響應接收
這個階段 Leader 掛掉摧冀,雖然數(shù)據(jù)在 Follower 節(jié)點處于未提交狀態(tài)(Uncommitted)但保持一致,重新選出 Leader 后可完成數(shù)據(jù)提交系宫,此時 Client 由于不知到底提交成功沒有索昂,可重試提交。針對這種情況 Raft 要求 RPC 請求實現(xiàn)冪等性扩借,也就是要實現(xiàn)內(nèi)部去重機制椒惨。
4. 數(shù)據(jù)到達 Leader 節(jié)點,成功復制到 Follower 部分節(jié)點潮罪,但還未向 Leader 響應接收
這個階段 Leader 掛掉康谆,數(shù)據(jù)在 Follower 節(jié)點處于未提交狀態(tài)(Uncommitted)且不一致凄杯,Raft 協(xié)議要求投票只能投給擁有最新數(shù)據(jù)的節(jié)點。所以擁有最新數(shù)據(jù)的節(jié)點會被選為 Leader 再強制同步數(shù)據(jù)到 Follower秉宿,數(shù)據(jù)不會丟失并最終一致戒突。
5. 數(shù)據(jù)到達 Leader 節(jié)點,成功復制到 Follower 所有或多數(shù)節(jié)點描睦,數(shù)據(jù)在 Leader 處于已提交狀態(tài)膊存,但在 Follower 處于未提交狀態(tài)
這個階段 Leader 掛掉,重新選出新 Leader 后的處理流程和階段 3 一樣忱叭。
6. 數(shù)據(jù)到達 Leader 節(jié)點隔崎,成功復制到 Follower 所有或多數(shù)節(jié)點,數(shù)據(jù)在所有節(jié)點都處于已提交狀態(tài)韵丑,但還未響應 Client
這個階段 Leader 掛掉爵卒,Cluster 內(nèi)部數(shù)據(jù)其實已經(jīng)是一致的,Client 重復重試基于冪等策略對一致性無影響撵彻。
7. 網(wǎng)絡分區(qū)導致的腦裂情況钓株,出現(xiàn)雙 Leader
網(wǎng)絡分區(qū)將原先的 Leader 節(jié)點和 Follower 節(jié)點分隔開,F(xiàn)ollower 收不到 Leader 的心跳將發(fā)起選舉產(chǎn)生新的 Leader陌僵。這時就產(chǎn)生了雙 Leader轴合,原先的 Leader 獨自在一個區(qū),向它提交數(shù)據(jù)不可能復制到多數(shù)節(jié)點所以永遠提交不成功碗短。向新的 Leader 提交數(shù)據(jù)可以提交成功受葛,網(wǎng)絡恢復后舊的 Leader 發(fā)現(xiàn)集群中有更新任期(Term)的新 Leader 則自動降級為 Follower 并從新 Leader 處同步數(shù)據(jù)達成集群數(shù)據(jù)一致。
綜上窮舉分析了最小集群(3 節(jié)點)面臨的所有情況偎谁,可以看出 Raft 協(xié)議都能很好的應對一致性問題总滩,并且很容易理解。
總結(jié)
就引用 Raft 論文最后的一節(jié)的綜述來總結(jié)本文吧巡雨。
算法以正確性闰渔、高效性、簡潔性作為主要設(shè)計目標鸯隅。
雖然這些都是很有價值的目標澜建,但這些目標都不會達成直到開發(fā)者寫出一個可用的實現(xiàn)向挖。
所以我們相信可理解性同樣重要蝌以。
深以為然,想想 Paxos 算法是 Leslie Lamport 在 1990 年就公開發(fā)表在了自己的網(wǎng)站上何之,想想我們是什么時候才聽說的跟畅?什么時候才有一個可用的實現(xiàn)?而 Raft 算法是 2013 年發(fā)表的溶推,大家在參考[5]上面可以看到有多少個不同語言開源的實現(xiàn)庫了徊件,這就是可理解性的重要性奸攻。