Raft 是一個一致性協議,提供幾個重要的功能:
- Leader 選舉
- 成員變更
- 日志復制
Simple Request Flow
這里首先介紹一下一次簡單的 Raft 流程:
- Leader 收到 client 發送的 request。
- Leader 將 request append 到自己的 log。
- Leader 將對應的 log entry 發送給其他的 follower。
- Leader 等待 follower 的結果,如果大多數節點提交了這個 log,則 apply。
- Leader 將結果返回給 client。
- Leader 繼續處理下一次 request。
可以看到,上面的流程是一個典型的順序操作,如果真的按照這樣的方式來寫,那性能是完全不行的。
Leader 節點對一致性的影響
Raft 協議強依賴 Leader 節點的可用性來確保集群數據的一致性。數據的流向只能從 Leader 節點向 Follower 節點轉移。當 Client 向集群 Leader 節點提交數據后,Leader 節點接收到的數據處於未提交狀態(Uncommitted),接着 Leader 節點會並發向所有 Follower 節點復制數據並等待接收響應,確保至少集群中超過半數節點已接收到數據后再向 Client 確認數據已接收。一旦向 Client 發出數據接收 Ack 響應后,表明此時數據狀態進入已提交(Committed),Leader 節點再向 Follower 節點發通知告知該數據狀態已提交。
Leader 節點對一致性的影響
Raft 協議強依賴 Leader 節點的可用性來確保集群數據的一致性。數據的流向只能從 Leader 節點向 Follower 節點轉移。當 Client 向集群 Leader 節點提交數據后,Leader 節點接收到的數據處於未提交狀態(Uncommitted),接着 Leader 節點會並發向所有 Follower 節點復制數據並等待接收響應,確保至少集群中超過半數節點已接收到數據后再向 Client 確認數據已接收。一旦向 Client 發出數據接收 Ack 響應后,表明此時數據狀態進入已提交(Committed),Leader 節點再向 Follower 節點發通知告知該數據狀態已提交。
在這個過程中,主節點可能在任意階段掛掉,看下 Raft 協議如何針對不同階段保障數據一致性的。
1. 數據到達 Leader 節點前
這個階段 Leader 掛掉不影響一致性,不多說。
2. 數據到達 Leader 節點,但未復制到 Follower 節點
這個階段 Leader 掛掉,數據屬於未提交狀態,Client 不會收到 Ack 會認為超時失敗可安全發起重試。Follower 節點上沒有該數據,重新選主后 Client 重試重新提交可成功。原來的 Leader 節點恢復后作為 Follower 加入集群重新從當前任期的新 Leader 處同步數據,強制保持和 Leader 數據一致。
3. 數據到達 Leader 節點,成功復制到 Follower 所有節點,但還未向 Leader 響應接收
這個階段 Leader 掛掉,雖然數據在 Follower 節點處於未提交狀態(Uncommitted)但保持一致,重新選出 Leader 后可完成數據提交,此時 Client 由於不知到底提交成功沒有,可重試提交。針對這種情況 Raft 要求 RPC 請求實現冪等性,也就是要實現內部去重機制。
4. 數據到達 Leader 節點,成功復制到 Follower 部分節點,但還未向 Leader 響應接收
這個階段 Leader 掛掉,數據在 Follower 節點處於未提交狀態(Uncommitted)且不一致,Raft 協議要求投票只能投給擁有最新數據的節點。所以擁有最新數據的節點會被選為 Leader 再強制同步數據到 Follower,數據不會丟失並最終一致。
5. 數據到達 Leader 節點,成功復制到 Follower 所有或多數節點,數據在 Leader 處於已提交狀態,但在 Follower 處於未提交狀態
這個階段 Leader 掛掉,重新選出新 Leader 后的處理流程和階段 3 一樣。
6. 數據到達 Leader 節點,成功復制到 Follower 所有或多數節點,數據在所有節點都處於已提交狀態,但還未響應 Client
這個階段 Leader 掛掉,Cluster 內部數據其實已經是一致的,Client 重復重試基於冪等策略對一致性無影響。
7. 網絡分區導致的腦裂情況,出現雙 Leader
網絡分區將原先的 Leader 節點和 Follower 節點分隔開,Follower 收不到 Leader 的心跳將發起選舉產生新的 Leader。這時就產生了雙 Leader,原先的 Leader 獨自在一個區,向它提交數據不可能復制到多數節點所以永遠提交不成功。向新的 Leader 提交數據可以提交成功,網絡恢復后舊的 Leader 發現集群中有更新任期(Term)的新 Leader 則自動降級為 Follower 並從新 Leader 處同步數據達成集群數據一致。
綜上窮舉分析了最小集群(3 節點)面臨的所有情況,可以看出 Raft 協議都能很好的應對一致性問題,並且很容易理解。
