先要明確的幾個概念
- Raft協(xié)議是基于paxos multi的桨螺,屬于全新優(yōu)化精簡版本耕魄,更加容易實現(xiàn)和理解。zookeeper用的zab協(xié)議跟raft基本一樣彭谁,就是心跳方向是反的吸奴,raft是leader向follower發(fā)送心跳,zab是follower向leader發(fā)送心跳詢問leader健康狀況。
- 再有一個就是则奥,raft考润、paxos、zab這些屬于強(qiáng)一致性協(xié)議读处,與之相對的還有弱一致性協(xié)議糊治,比如DNS的工作原理,比如Cassandra和redis cluster模式用到的gossip協(xié)議等罚舱。弱一致性也叫最終一致性井辜。一般來說弱一致性的系統(tǒng)性能要好于強(qiáng)一致性。對讀寫并發(fā)要求比較高的場景應(yīng)該想辦法優(yōu)先使用弱一致性協(xié)議管闷。
解決問題的核心
Raft將狀態(tài)機(jī)復(fù)制(state machine replication)或者說分布式一致性問題分解為3個子問題:
- leader選舉
- log復(fù)制
- 異常狀況下的數(shù)據(jù)安全性:leader宕機(jī)粥脚、選主平票、分區(qū)腦裂
leader選舉
- 集群啟動初始狀態(tài)下所有節(jié)點都是follower包个,這時候follower會觸發(fā)選舉刷允。當(dāng)follower無法在本地計時的隨機(jī)超時時間內(nèi)收到leader的心跳包,也會觸發(fā)選舉碧囊。
- 達(dá)到自己超時時間的follower就變成Candidate树灶,然后會向集群中的其他節(jié)點發(fā)送拉票請求,每個節(jié)點會投票給最先發(fā)給自己拉票請求的節(jié)點糯而,當(dāng)某個節(jié)點獲得超過半數(shù)節(jié)點的票時天通,會當(dāng)選為新的leader。每個leader任期內(nèi)都有一個唯一的term熄驼,表示當(dāng)前集群處于這個節(jié)點作為leader這樣一個階段像寒。
Log復(fù)制
- 首先所有的寫請求必須都由leader處理
- leader會先寫本地的log但未真正去寫數(shù)據(jù)、也就是這個寫在本地是寫未提交的這樣一個中間狀態(tài)谜洽。然后在心跳包中包含寫請求,將操作給follower吴叶。follower收到寫請求之后阐虚,也在本地寫log,進(jìn)入寫未提交狀態(tài)蚌卤,同時回復(fù)leader实束。
- leader收到超過半數(shù)的follower的回復(fù)之后,會先commit提交本地的寫log逊彭,數(shù)據(jù)真正寫入咸灿、然后返回客戶端數(shù)據(jù)寫入成功。最后通知各個follower:leader已提交該寫操作侮叮,各位也提交這個操作避矢。
- follower收到leader的提交通知之后,提交自己本地對應(yīng)的寫log。整個過程結(jié)束审胸。
ps: leader應(yīng)該是會為每個follower維護(hù)一個同步進(jìn)度或者說日志offset的表亥宿,這樣可以清楚知道每個follower的數(shù)據(jù)log復(fù)制的進(jìn)度。
比如某個follower宕機(jī)了一陣子砂沛,再恢復(fù)的時候leader仍然會幫它把落下的這段時間的課補(bǔ)上烫扼。因為leader知道它的復(fù)制進(jìn)度。
異常狀態(tài)下的數(shù)據(jù)安全性
leader宕機(jī)
每個follower會不斷的隨機(jī)設(shè)置一個超時時間timeout碍庵,然后從0開始計時映企,在timeout之內(nèi)收到leader的心跳包則會重新從0開始計時。
一旦計時到timeout仍未收到leader的心跳包静浴,這個follower就會啟動 “變candidate -> 向其他節(jié)點拉票 -> 嘗試得到超過半數(shù)票成為leader” 這樣一個流程堰氓。
選主平票
如果出現(xiàn)這個狀況,平票的兩個節(jié)點會各自再來一次隨機(jī)timeout倒數(shù)马绝,然后重新拉票豆赏。這樣因為兩個隨機(jī)timeout總會有一個時間差的存在、基本大概率兩者之間會產(chǎn)生一個勝出者了富稻。
分區(qū)腦裂
這里體現(xiàn)出為什么節(jié)點個數(shù)要定奇數(shù)個了掷邦。
如果是偶數(shù)個,那么發(fā)生分區(qū)的時候可能會出現(xiàn)兩個分區(qū)的節(jié)點一樣多的情況:沒有l(wèi)eader的區(qū)無法選出新leader椭赋,而有l(wèi)eader的區(qū)在寫日志復(fù)制時無法得到超過半數(shù)的follower的回復(fù)(自己也算)抚岗、無法commit所以無法回復(fù)客戶端已寫入、只能回復(fù)unknown哪怔。這樣整個系統(tǒng)呈現(xiàn)出不可用的狀態(tài)宣蔚。
而奇數(shù)個節(jié)點的集群發(fā)生分區(qū),總會有一大一小兩個分區(qū):如果leader在大分區(qū)认境、可以收到半數(shù)以上的回復(fù)胚委、可以commit寫日志,集群正常工作叉信;如果leader在小分區(qū)亩冬,由于大分區(qū)超半數(shù)節(jié)點、會選舉出來新leader硼身,當(dāng)小分區(qū)的舊leader收到寫請求之后硅急,無法達(dá)到半數(shù)回復(fù),寫會失敗佳遂。這樣客戶端可以選擇新leader進(jìn)行請求营袜,集群整體可用。
ps:分區(qū)恢復(fù)之后丑罪、舊leader收到新leader的心跳包會發(fā)現(xiàn)term比自己的新荚板,所以會變成follower與新leader進(jìn)行同步凤壁。