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