[分布式一致性协议] ------ raft协议的解释与理解
前言
在分布式系統中,為了保證容錯性,一般會維護多個副本集群,提高系統的高可用,但與之帶來的問題就是多個副本的一致性(consensus)問題。
我們認為,對于一個具有一致性的的集群中,同一時刻所有節點對存儲在其中的值都應該是相同的,并且在集群大部分節點可用時,集群也是可用的。
能完成這種一致性的協議,就叫一致性協議。
常見的分布式一致性協議有:
- 兩階段提交協議,
- 三階段提交協議,
- 向量時鐘,
- RWN協議,
- paxos協議,
- Raft協議等
所以本文說的raft協議,就是一種分布式一致性協議,他定義了易于實現一致性協議的實施標準,可以維護多個副本的一致性。
raft協議中,我們有以下規定:
1.集群中的節點,只有三種角色(leader,follower,candidate)
leader:
領導者,只有leader才能處理客戶端請求,同步數據到其他實例。同時負責周期性的發送心跳包(heartbeat)到follower,目的是為了維持自己的leader角色。算法保證任何時刻都只存在一個合法的leader。
follower:
跟隨者,被動接收RPC請求并做響應,比如leader請求添加日志數據,candidate請求選舉。follower本身是被動的,不會主動發起RPC。
candidate:
候選人,當follower一段時間內沒有收到leader的heartbeat(可能是leader掛了,可能是自己網絡出問題了),就認為當前leader失效,轉變為candidate角色。
2.term:任期,由一個唯一的id標識,每選舉一次,term就會自增,leader永遠是有最新的term。每個term一開始就會先進行選舉:
3.LogEntry:客戶端的一個命令對應一個LogEntry
raft協議中有兩個重點(選舉leader和日志復制):
1.Leader election(選舉leader)
在上圖這個選舉的過程中,對于某個候選人,會有以下三種情況:
1.自己成為leader
獲取相同term下超過半數的投票。
2.別人成為leader
candidate在等待投票的過程中,可能收到其他實例的AppendEntries RPCs,
如果發現RPC里參數的term >= 自身的currentTerm,那么就意識到已經有新的leader選出,自己敗選,轉為follower.
如果收到其他實例的RequestVote RPCs,發現RPC里的參數term > 自身的currentTerm,那么就意識到已經有新的term開始,轉為follower.
3.沒有選出leader
當投票被瓜分,沒有任何一個candidate收到了majority的vote時,沒有leader被選出。
這種情況下,每個candidate等待的投票的過程就超時了,接著candidates都會將本地的current_term_id再加1,發起拉票進行新一輪的leader election。
此外,影響成為leader的因素,不止任期,還有日志長度,日志長度的優先級低于任期的優先級。
總結來說,當一個實例收到RequestVote RPC時,要先判斷任期是否大于本身,如果是,就直接投票,如果不是,再判斷這個rpc的發送者的日志長度是不是小于等于自己,如果不是,就拒絕投票。
舉個例子:
有A B C D E 5個實例(1)A當選為leader,同步數據到D E并commit,之后D E宕機(2)此時A網絡斷連,B C都成為candidate,不斷自增term,但由于只有兩個實例,無法滿足大多數的條件(3)A網絡恢復,此時B C term都較高,因此A接收到RequestVote后轉為follower(4)A B C 3個實例,如果B C隨機超時時間總是較短,那么總是能發出RequestVote RPC使得A轉為follower一直無法參與選舉(5)由于A的日志里已經有commit的數據,此時規則需要保證A勝出對于剛剛網絡恢復的A來說,如果收到B或C的RequestVote RPC,會因為自己的日志長度大于B或C,從而拒絕投票,那么B或C就得不到大多數的投票(5個實例,大多數至少是3票),最終引起選舉超時,然后ABC將會重新開始選舉,直到A發起投票,成為leader。再說說上面例子中的選舉超時:
為了盡可能避免平票的問題,同時就算平票,也能快速解決,選舉超時的時間是很講究的,官網給定的是在(150ms~300ms)直接隨機取一個超時時間。如此一來,大多數情況下就只有一個節點會發起選舉。即使出現平票,每個節點又會在一個隨機時間后(重置timer)開始新的選舉,避免了重復平票。(注意,這種隨機的超時時間,是一種思想,不僅在選舉中會用到,我們也要在其他場景中想到這種方案。)選舉超時重置的3種情況:
(1)candidate開始選舉后,要重置timer(2)如果收到RequestVote,只有在投票給對方轉為follower的情況下,才重置(3)如果收到AppendEntries,而且收到的term比自身大,則轉為follwer并重置2.Log Replication (日志復制)
最上面這個是新leader,a~f是follower,每個格子代表一條log entry,格子內的數字代表這個log entry是在哪個term上產生的。
(1)a、b少數據
(2)c、d多數據
(3)e、f數據沖突
為什么leader和follower的日志是一致的:
需要有一種機制來讓leader和follower對log達成一致,leader會為每個follower維護一個nextIndex(比如上圖的1到12),表示leader給各個follower發送的下一條log entry在log中的index,初始化為leader的最后一條log entry的下一個位置。
leader給follower發送AppendEntriesRPC消息,帶著(term_id, (nextIndex-1)), term_id即(nextIndex-1)這個槽位的log entry的term_id,
follower接收到AppendEntriesRPC后,會從自己的log中找是不是存在這樣的log entry,如果不存在,就給leader回復拒絕消息,然后leader則將nextIndex減1,再重復,直到AppendEntriesRPC消息被接收。
以leader和b為例:
初始化,nextIndex為11,leader給b發送AppendEntriesRPC(6,10),b在自己log的10號槽位中沒有找到term_id為6的log entry。則給leader回應一個拒絕消息。接著,leader將nextIndex減一,變成10,然后給b發送AppendEntriesRPC(6, 9),b在自己log的9號槽位中同樣沒有找到term_id為6的log entry。循環下去,直到leader發送了AppendEntriesRPC(4,4),b在自己log的槽位4中找到了term_id為4的log entry,接收了消息。隨后,leader就可以從槽位5開始給b推送日志。最后附上raft協議的原論文和中文翻譯
原文:https://ramcloud.atlassian.net/wiki/download/attachments/6586375/raft.pdf
翻譯:https://blog.csdn.net/chenhaifeng2016/article/details/54880091 (翻譯難免會附加譯者的思想,建議最好還是看原文,能感受到原作者的思想)
總結
以上是生活随笔為你收集整理的[分布式一致性协议] ------ raft协议的解释与理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在python中使用什么工具管理模块_怎
- 下一篇: 计算机考试用英语怎么说,“全国大学生计算