一致性协议raft详解(一):raft整体介绍
一致性協議raft詳解(一):raft介紹
- 前言
- 概述
- raft獨特的特性
- raft集群的特點
- raft中commit何意?
- raft leader election
- log replication
- 網絡分區
- Symmetric network partitioning
- Asymmetric network partitioning
- StepDown
- raft沖突解決方法
- 參考鏈接
前言
有關一致性協議的資料網上有很多,當然錯誤也有很多。筆者在學習的過程中走了不少彎路。現在回過頭來看,最好的學習資料就是Leslie Lamport和Diego Ongaro的數篇論文、Ongaro在youtube上發的三個視頻講解,以及何登成的ppt。
本系列文章是只是筆者在學習一致性協議過程中的摘抄和總結,有疏漏之處敬請諒解,歡迎討論。
概述
一致性協議的目的是實現CAP,最好在CA之間有很好的平衡,既保證高可用,又保證一致性
所以這類算法大概涉及兩個方面
raft獨特的特性
- 強領導者:和其他一致性算法相比,**Raft 使用一種更強的領導能力形式。**比如,日志條目只從領導者發送給其他的服務器。這種方式簡化了對復制日志的管理并且使得 Raft 算法更加易于理解。
- 領導選舉:Raft 算法使用一個隨機計時器來選舉領導者。這種方式只是在任何一致性算法都必須實現的心跳機制上增加了一點機制。在解決沖突的時候會更加簡單快捷。
- 成員關系調整:Raft 使用一種共同一致的方法來處理集群成員變換的問題,在這種方法下,處于調整過程中的兩種不同的配置集群中大多數機器會有重疊,這就使得集群在成員變換的時候依然可以繼續工作。
- 如果在不同的日志中的兩個條目擁有相同的索引和任期號,那么他們存儲了相同的指令。因為同一個任期只有一個leader,leader最多在一個任期里在指定的一個日志索引位置創建一條日志條目
- 如果在不同的日志中的兩個條目擁有相同的索引和任期號,那么他們之前的所有日志條目也全部相同。因為日志在raft節點中必須是順序添加的。leader保存著每個follower當前的日志進展,并持續給follower推送
- 但是某條log到底能不能被commit,還是要看他有沒有被大多數節點接受(Figure 8) (并且整個集群具備冪等性)
| 選舉安全特性 | 對于一個給定的任期號,最多只會有一個領導人被選舉出來(5.2 節) |
| 領導人只附加原則 | 領導人絕對不會刪除或者覆蓋自己的日志,只會增加(5.3 節) |
| 日志匹配原則 | 如果兩個日志在相同的索引位置的日志條目的任期號相同,那么我們就認為這個日志從頭到這個索引位置之間全部完全相同(5.3 節) |
| 領導人完全特性 | 如果某個日志條目在某個任期號中已經被提交,那么這個條目必然出現在更大任期號的所有領導人中(5.4 節) |
| 狀態機安全特性 | 如果一個領導人已經將給定的索引值位置的日志條目應用到狀態機中,那么其他任何的服務器在這個索引位置不會應用一個不同的日志(5.4.3 節) |
raft集群的特點
摘自何登成老師的ppt
- 系統存在一個Leader角色(Proposer),接受Clients發過來的所有讀寫請求
- Leader負責與所有的Followers(Acceptors)通信,將提案/Value/變更復制到所有Followers,同時收集多數派Followers的應答
- 少數派宕機,不會影響系統整體的可用性
- Leader日常維護與所有Followers的心跳
- Leader宕機,會觸發系統自動重新選主,選主期間系統對外不可服務
raft中commit何意?
The leader decides when it is safe to apply a log entry to the state machines; such an entry is called committed.
raft作者說只要leader把當前log寫入自己的RSM中,就算是commit了(該日志已經被系統中大部分節點接受),并且提供raft一致性協議的以下兩點保證:
Our goal for Raft is to implement linearizable semantics (each operation appears to execute instantaneously, exactly once, at some point between its invocation and its response).
raft leader election
leader選舉原則:最大提交原則: During elections, choose candidate with log most likely to contain all committed entries
- Follower在收到Leader或者Candidate的RPC請求的情況下一直保持Follower狀態。而當一段時間內(election timeout)沒有收到請求則認為沒有Leader節點而出發選舉流程。
- 選舉開始之后,自己作為candidate,先投自己一票,向其他candidate發選舉請求,如果自己收到選舉請求并且自己沒有選舉過,就把票投出去
- 某臺機器收到投票過半,則成為主
- 選舉windows的時長是隨機決定的(150ms-300ms) electionTimout,這種方式只是在任何一致性算法都必須實現的心跳機制上增加了一點機制。在解決沖突的時候會更加簡單快捷。
- 如果follower在election timeout超時了,會成為candidate;如果heartbeat timeout超時了,也會成為candidate
- 其實不太會出現那種大家一起變成candidate,導致投票一直失敗那種情況,因為electionTimout是一個隨機的,包括服務剛起來的時候也會等一個隨機的時間
- 安全性:
- 擁有最新的已提交的log entry的Follower才有資格成為Leader(相當于是term(任期)和log entry都要最大)
- 這個保證是在RequestVote RPC中做的,Candidate在發送RequestVote RPC時,要帶上自己的最后一條日志的term和log index,其他節點收到消息時,如果發現自己的日志比請求中攜帶的更新,則拒絕投票。日志比較的原則是,如果本地的最后一條log entry的term更大,則term大的更新,如果term一樣大,則log index更大的更新。
- 這點隱含了一個事實:如果一個candidate能當選主,那么它一定包含了最新的日志,并且最新這條日志被半數以上節點承認。
- 抽屜原理,選舉出來的Leader是多數中數據最新的,一定包含已經在多數節點上commit的數據
- 這點隱含了一個事實:如果一個candidate能當選主,那么它一定包含了最新的日志,并且最新這條日志被半數以上節點承認。
- 這個保證是在RequestVote RPC中做的,Candidate在發送RequestVote RPC時,要帶上自己的最后一條日志的term和log index,其他節點收到消息時,如果發現自己的日志比請求中攜帶的更新,則拒絕投票。日志比較的原則是,如果本地的最后一條log entry的term更大,則term大的更新,如果term一樣大,則log index更大的更新。
- Leader只能推進commit index來提交當前term的已經復制到大多數服務器上的日志,舊term日志的提交要等到提交當前term的日志來間接提交(log index 小于 commit index的日志被間接提交)。
- 還有一種實現方式是,保證只讓最大commit index的人做leader,就算是因為網絡分區導致一些stale節點的term值很大,leader也會先收到這個leader選舉rpc之后追齊term(StepDown),然后再次成為leader,這也就是為什么braft的文檔中說原始的RAFT論文中對非對稱的網絡劃分處理不好
- 擁有最新的已提交的log entry的Follower才有資格成為Leader(相當于是term(任期)和log entry都要最大)
- 在等待投票的時候,候選人可能會從其他的服務器接收到聲明它是leader的附加日志項 RPC。如果這個leader的任期號(包含在此次的 RPC中)不小于候選人當前的任期號,那么候選人會承認leader合法并回到跟隨者狀態。 如果此次 RPC 中的任期號比自己小,那么候選人就會拒絕這次的 RPC 并且繼續保持候選人狀態。
log replication
網絡分區
主要摘自baidu braft文章
Symmetric network partitioning
原始的RAFT論文中對于對稱網絡劃分的處理是,一個節點再次上線之后,Leader接收到高于currentTerm的RequestVote請求就進行StepDown。這樣即使這個節點已經通過RemovePeer刪除了,依然會打斷當前的Lease,導致復制組不可用。對于這種case可以做些特殊的處理:Leader不接收RequestVote請求,具體情況如下:
這樣,屬于PeerSet中的節點最終能夠加入,不屬于PeerSet的節點不會加入也不會破壞。如果網絡劃分是因為節點故障導致的,那么穩定的多數復制組不會收到更高term的AppendEntries應答,Leader不會StepDown,這樣節點可以安靜的加入集群。
Asymmetric network partitioning
原始的RAFT論文中對非對稱的網絡劃分處理不好,比如S1、S2、S3分別位于三個IDC,其中S1和S2之間網絡不通,其他之間可以聯通。這樣一旦S1或者是S2搶到了Leader,另外一方在超時之后就會觸發選主,例如S1為Leader,S2不斷超時觸發選主,S3提升Term打斷當前Lease,從而拒絕Leader的更新。這個時候可以增加一個trick的檢查,每個Follower維護一個時間戳記錄收到Leader上數據更新的時間,只有超過ElectionTImeout之后才允許接受Vote請求。這個類似Zookeeper中只有Candidate才能發起和接受投票,就可以保證S1和S3能夠一直維持穩定的quorum集合,S2不能選主成功。
StepDown
RAFT原始協議中Leader收到任何term高于currentTerm的請求都會進行StepDown,在實際開發中應該在以下幾個時刻進行StepDown:
raft沖突解決方法
在 Raft 算法中,leader處理不一致是通過強制follower直接復制自己的日志來解決的。這意味著在follower中的沖突的日志條目會被leader的日志覆蓋。
- 要使得跟隨者的日志進入和自己一致的狀態,leader必須找到最后兩者達成一致的地方(最簡單的方法就是領導者一個個的減少index去試,看哪個能append成功),然后刪除從那個點之后的所有日志條目,發送自己的日志給跟隨者。
參考鏈接
總結
以上是生活随笔為你收集整理的一致性协议raft详解(一):raft整体介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么是SPDK,以及什么场景需要它
- 下一篇: 一致性协议raft详解(二):安全性