1.Consensus一致性的理解
1)它是指多個服務(wù)器在狀態(tài)達(dá)成一致,但是在一個分布式系統(tǒng)中,因為各種意外可能,有的服務(wù)器可能會崩潰或變得不可靠,它就不能和其他服務(wù)器達(dá)成一致狀態(tài)。這樣就需要一種Consensus協(xié)議,一致性協(xié)議是為了確保容錯性,也就是即使系統(tǒng)中有一兩個服務(wù)器當(dāng)機,也不會影響其處理過程。
2)Paxos和Raft都是為了實現(xiàn)Consensus一致性這個目標(biāo),這個過程如同選舉一樣,參選者需要說服大多數(shù)選民(服務(wù)器)投票給他,一旦選定后就跟隨其操作。Paxos和Raft的區(qū)別在于選舉的具體過程不同。
3)Paxos難于理解,更難以實現(xiàn),但是Raft是一個為真實世界應(yīng)用建立的協(xié)議,主要注重協(xié)議的落地性和可理解性。
4)為了以容錯方式達(dá)成一致,我們不可能要求所有服務(wù)器100%都達(dá)成一致狀態(tài),只要超過半數(shù)的大多數(shù)服務(wù)器達(dá)成一致就可以了,假設(shè)有N臺服務(wù)器,N/2 +1 就超過半數(shù),代表大多數(shù)了
2.在一個Raft協(xié)議中任何時候服務(wù)器都能扮演這三類角色:
leader? 領(lǐng)導(dǎo)者:處理所有客戶端交互,日志復(fù)制等,一般一次只有一個Leader.
follower? 群眾? :類似選民,完全被動
Candidate 候選人:類似Proposer律師,可以被選為一個新的領(lǐng)導(dǎo)人
選舉簡單流程:
剛開始沒有領(lǐng)袖,所有集群中的參與者都是群眾,那么首先開啟一輪大選,在大選期間所有群眾都能參與競選,這時所有群眾的角色就變成了候選人,民主投票選出領(lǐng)袖后就開始了這屆領(lǐng)袖的任期,然后選舉結(jié)束,所有除領(lǐng)袖的候選人又變回群眾角色服從領(lǐng)袖領(lǐng)導(dǎo)。

3.leader選舉過程
1)每個節(jié)點均有一個競選超時時間(150~300ms隨機)
2)一個最小的 Raft 民主集群需要三個參與者,這樣才可能投出多數(shù)票。初始狀態(tài) ABC 都是 Follower,然后發(fā)起選舉這時有三種可能情形發(fā)生。
3)下圖中前二種都能選出 Leader
4)第三種則表明本輪投票無效(Split Votes),每方都投給了自己,結(jié)果沒有任何一方獲得多數(shù)票。之后每個參與方隨機休息一陣(Election Timeout)重新發(fā)起投票直到一方獲得多數(shù)票。這里的關(guān)鍵就是隨機 timeout,最先從 timeout 中恢復(fù)發(fā)起投票的一方向還在 timeout 中的另外兩方請求投票,這時它們就只能投給對方了,很快達(dá)成一致。

選出 Leader 后,Leader 通過定期向所有 Follower 發(fā)送心跳信息維持其統(tǒng)治。若 Follower 一段時間未收到 Leader 的心跳則認(rèn)為 Leader 可能已經(jīng)掛了再次發(fā)起選主過程。
5)還有第四種情況:

Splite Vote是因為如果同時有兩個或者多個候選人向大家邀票,這時通過類似加時賽來解決,兩個候選者在一段timeout比如300ms互相不服氣的等待以后,因為雙方得到的票數(shù)是一樣的,一半對一半,那么在300ms以后,再由這兩個候選者發(fā)出邀票,這時同時的概率大大降低,那么首先發(fā)出邀票的的候選者得到了大多數(shù)同意,成為領(lǐng)導(dǎo)者Leader,而另外一個候選者后來發(fā)出邀票時,那些Follower選民已經(jīng)投票給第一個候選者,不能再投票給它,它就成為落選者了,最后這個落選者也成為普通Follower一員了。
4.日志復(fù)制
日志復(fù)制,是指主節(jié)點將每次操作形成日志條目,并持久化到本地磁盤,然后通過網(wǎng)絡(luò)IO發(fā)送給其他節(jié)點。日志中存在四個位置,type【只有兩種狀態(tài),一種是0表示Normal,1表示ConfChange(ConfChange表示 Etcd 本身的配置變更同步,比如有新的節(jié)點加入等),日志的邏輯時鐘(TERM)和日志編號(INDEX)還有data數(shù)據(jù)部分。其他節(jié)點根據(jù)日志的邏輯時鐘(TERM)和日志編號(INDEX)來判斷是否將該日志記錄持久化到本地。當(dāng)主節(jié)點收到包括自己在內(nèi)超過半數(shù)節(jié)點成功返回,那么認(rèn)為該日志是可提交的(committed),并將日志輸入到狀態(tài)機,將結(jié)果返回給客戶端。
這里需要注意的是,每次選主都會形成一個唯一的TERM編號,相當(dāng)于邏輯時鐘。每一條日志都有全局唯一的編號。

主節(jié)點通過網(wǎng)絡(luò)IO向其他節(jié)點追加日志。若某節(jié)點收到日志追加的消息,首先判斷該日志的TERM是否過期,以及該日志條目的INDEX是否比當(dāng)前以及提交的日志的INDEX跟早。若已過期,或者比提交的日志更早,那么就拒絕追加,并返回該節(jié)點當(dāng)前的已提交的日志的編號。否則,將日志追加,并返回成功。
當(dāng)主節(jié)點收到其他節(jié)點關(guān)于日志追加的回復(fù)后,若發(fā)現(xiàn)有拒絕,則根據(jù)該節(jié)點返回的已提交日志編號,發(fā)生其編號下一條日志。
主節(jié)點像其他節(jié)點同步日志,還作了擁塞控制。具體地說,主節(jié)點發(fā)現(xiàn)日志復(fù)制的目標(biāo)節(jié)點拒絕了某次日志追加消息,將進入日志探測階段,一條一條發(fā)送日志,直到目標(biāo)節(jié)點接受日志,然后進入快速復(fù)制階段,可進行批量日志追加。
raft協(xié)議本身不關(guān)心應(yīng)用數(shù)據(jù)。按照日志復(fù)制的邏輯,我們可以看到,集群中慢節(jié)點不影響整個集群的性能。另外一個特點是,數(shù)據(jù)只從主節(jié)點復(fù)制到Follower節(jié)點,這樣大大簡化了邏輯流程。
5.leader節(jié)點對一致性的影響(安全性)
Raft 協(xié)議強依賴 Leader 節(jié)點的可用性來確保集群數(shù)據(jù)的一致性。數(shù)據(jù)的流向只能從 Leader 節(jié)點向 Follower 節(jié)點轉(zhuǎn)移。當(dāng) Client 向集群 Leader 節(jié)點提交數(shù)據(jù)后,Leader 節(jié)點接收到的數(shù)據(jù)處于未提交狀態(tài)(Uncommitted),接著 Leader 節(jié)點會并發(fā)向所有 Follower 節(jié)點復(fù)制數(shù)據(jù)并等待接收響應(yīng),確保至少集群中超過半數(shù)節(jié)點已接收到數(shù)據(jù)后再向 Client 確認(rèn)數(shù)據(jù)已接收。一旦向 Client 發(fā)出數(shù)據(jù)接收 Ack 響應(yīng)后,表明此時數(shù)據(jù)狀態(tài)進入已提交(Committed),Leader 節(jié)點再向 Follower 節(jié)點發(fā)通知告知該數(shù)據(jù)狀態(tài)已提交。

6.但是在這個過程中的任何時候都會出現(xiàn)leader掛掉的情況,一致性該怎樣保持?
1)數(shù)據(jù)到達(dá)leader節(jié)點之前(這個階段 Leader 掛掉不影響一致性,不多說):

2)數(shù)據(jù)到達(dá) Leader 節(jié)點,但未復(fù)制到 Follower 節(jié)點

這個階段 Leader 掛掉,數(shù)據(jù)屬于未提交狀態(tài),Client 不會收到 Ack 會認(rèn)為超時失敗可安全發(fā)起重試。Follower 節(jié)點上沒有該數(shù)據(jù),重新選主后 Client 重試重新提交可成功。原來的 Leader 節(jié)點恢復(fù)后作為 Follower 加入集群重新從當(dāng)前任期的新 Leader 處同步數(shù)據(jù),強制保持和 Leader 數(shù)據(jù)一致。
3)?數(shù)據(jù)到達(dá) Leader 節(jié)點,成功復(fù)制到 Follower 所有節(jié)點,但還未向 Leader 響應(yīng)接收、

這個階段 Leader 掛掉,雖然數(shù)據(jù)在 Follower 節(jié)點處于未提交狀態(tài)(Uncommitted)但保持一致,重新選出 Leader 后可完成數(shù)據(jù)提交,此時 Client 由于不知到底提交成功沒有,可重試提交。針對這種情況 Raft 要求 RPC 請求實現(xiàn)冪等性,也就是要實現(xiàn)內(nèi)部去重機制。
4)數(shù)據(jù)到達(dá) Leader 節(jié)點,成功復(fù)制到 Follower 部分節(jié)點,但還未向 Leader 響應(yīng)接收

這個階段 Leader 掛掉,數(shù)據(jù)在 Follower 節(jié)點處于未提交狀態(tài)(Uncommitted)且不一致,Raft 協(xié)議要求投票只能投給擁有最新數(shù)據(jù)的節(jié)點。所以擁有最新數(shù)據(jù)的節(jié)點會被選為 Leader 再強制同步數(shù)據(jù)到 Follower,數(shù)據(jù)不會丟失并最終一致
5)數(shù)據(jù)到達(dá) Leader 節(jié)點,成功復(fù)制到 Follower 所有或多數(shù)節(jié)點,數(shù)據(jù)在 Leader 處于已提交狀態(tài),但在 Follower 處于未提交狀態(tài),這個階段 Leader 掛掉,重新選出新 Leader 后的處理流程和階段 3 一樣。

6)數(shù)據(jù)到達(dá) Leader 節(jié)點,成功復(fù)制到 Follower 所有或多數(shù)節(jié)點,數(shù)據(jù)在所有節(jié)點都處于已提交狀態(tài),但還未響應(yīng) Client。這個階段 Leader 掛掉,Cluster 內(nèi)部數(shù)據(jù)其實已經(jīng)是一致的,Client 重復(fù)重試基于冪等策略對一致性無影響

7)?網(wǎng)絡(luò)分區(qū)導(dǎo)致的腦裂情況,出現(xiàn)雙 Leader
網(wǎng)絡(luò)分區(qū)將原先的 Leader 節(jié)點和 Follower 節(jié)點分隔開,F(xiàn)ollower 收不到 Leader 的心跳將發(fā)起選舉產(chǎn)生新的 Leader。這時就產(chǎn)生了雙 Leader,原先的 Leader 獨自在一個區(qū),向它提交數(shù)據(jù)不可能復(fù)制到多數(shù)節(jié)點所以永遠(yuǎn)提交不成功。向新的 Leader 提交數(shù)據(jù)可以提交成功,網(wǎng)絡(luò)恢復(fù)后舊的 Leader 發(fā)現(xiàn)集群中有更新任期(Term)的新 Leader 則自動降級為 Follower 并從新 Leader 處同步數(shù)據(jù)達(dá)成集群數(shù)據(jù)一致。
