一致性原理學習Raft&Consul

目錄

 

1 簡介

1.1 一致性簡介

1.1.1 一致性的描述性定義

1.1.2 一致性和CAP理論

1.2 一致性協議/算法發展歷程

2 Raft協議原理

2.1 Raft協議簡介

2.1 Leader選舉

2.1.1 選舉簡述

2.1.2 選舉細節

2.1.3 實例分析-異常情況

2.1.4 選舉問題分析

2.2 日誌複製

2.2.1 日誌複製原理

2.2.2 日誌複製異常分析

2.2.3 日誌複製問題記錄

2.3 成員變更

3 Consul與Raft

 

0 參考資料


1 簡介

1.1 一致性簡介

1.1.1 一致性的描述性定義

一致性是指分佈式系統中的多個節點在數據層面達到一致。多個計算機就某個值達成了一致。比如a=2,所有計算機達成一致之後他們的內存中a就是等於2且不可改變。此決定一旦達成不可更改。由於各個計算機是相互獨立的,故障隨時可能發生,在所有計算機上總是達成一致是不可能的。我們當然可以設計一個所有計算機必須都正常才能達成一致的系統,但是一旦發生故障,這個一致性系統就會變得不可用,抵禦風險的能力比較弱。所以主流的一致性協議都是能夠容忍少數(小於50%)的計算機故障。

 

1.1.2 一致性和CAP理論

分佈式CAP理論 https://baike.baidu.com/item/CAP#3

對於大部分分佈式系統而言,P(分區容錯)都是要保證,因此權衡一般都在A(可用性)和C(一致性)中做權衡。

 

由此衍生出三種強弱不同的一致性協議。強一致性協議、弱一致性協議、最終一致性。

強一致性:客戶端往“主”中寫入數據的時候,主再往“從”中寫,直到大部分“從”寫成功,即可返回客戶端寫成功,返回了寫成功,從任意節點讀的內容都是"寫"之後的狀態

弱一致性:寫之後的內容,不一定能立馬讀出來,從不同節點讀的內容也可能不一致。但是一般最終都是一致的。

 

對於一個系統而言,談及其一致性的時候我們一般說的都是其對外的一致性。

Raft從外部來看,是強一致性。其實其內部各個節點之間並不是在每個時刻都是一致的,很明顯這是絕對做不到的

Gossip協議就是最終一致性。

 

用戶更新網站頭像,在某個時間點,用戶向主庫發送更新請求,不久之後主庫就收到了請求。在某個時刻,主庫又會將數據變更轉發給自己的從庫。最後,主庫通知用戶更新成功。銀行轉賬購也類似。

如果在返回“更新成功”並使新頭像對其他用戶可見之前,主庫需要等待從庫的確認,確保從庫已經收到寫入操作,那麼複製是同步的,即強一致性。如果主庫寫入成功後,不等待從庫的響應,直接返回“更新成功”,則複製是異步的,即弱一致性。

 

1.2 一致性協議/算法發展歷程

 

兩階段提交協議 --> Paxos --> ZAB --> Raft。

協議名稱

特點

產品代表

備註

Paxos

  1. 理論強,一般作爲經典教學示例

  2. 非常抽象,難以理解

  3. 缺乏工程實踐基礎

 

 

ZAB

  1. 對Paxos進行了很多的改進與優化

  2. 但是依然非常複雜難懂

ZooKeeper

 

Raft

  1. 從論文中就可以看出,設計的重要目標就是易懂。

  2. 另一個重要的設計目標就是易於工程實現和使用

Consul

K8s(Edct)

Redis Cluster

TiDB

區塊鏈共識算法

  1. 論文參考文末鏈接

  2. 實現一個工業級的Raft依然不易,Consul實現了,百度的開源braft也實現,阿里也實現了一個

 

2 Raft協議原理

2.1 Raft協議簡介

論文的第一句話是:

Raft is a consensus algorithm for managing a replicated log.

這句話說了Raft協議要解決的問題和解決問題的手段(非全部手段,但是是最重要的手段)。

 

爲了達到一致,Raft做了以下工作,強化Leader角色的功能,Raft請求都要經過Leader,因此保證集羣只有一個Leader非常重要。

Raft 一致性協議相對來說易於實現主要歸結爲以下幾個原因:

  • 模塊化的拆分:把一致性協議劃分爲 Leader 選舉、MemberShip 變更、日誌複製、SnapShot 等相對比較解耦的模塊;

  • 設計的簡化:比如不允許類似 Paxos 算法的亂序提交、使用 Randomization 算法設計 Leader Election 算法以簡化系統的狀態,只有 Leader、Follower、Candidate 等等。

 

2.1 Leader選舉

2.1.1 選舉簡述

爲了保證集羣在任何時刻只有一個Leader,選舉策略的設計顯得尤爲重要。Leader選舉涉及到以下問題:

  1. 哪些節點有被選舉權(參選)/何時發起選舉

  2. 哪些節點有投票權/何時投票/投給誰

保證只有一個Leader的確切含義是保證只有一個Leader會分發日誌,可能集羣中有不止一隻節點認爲自己是Leader,但是實質上多數認爲是Leader那個纔是真正的Leader)。

 

Raft將節點有三種狀態/角色:Leader、Follower、Candidate。

http://thesecretlivesofdata.com/raft/

 

 

如上圖所示,整個狀態的流轉過程是:

每個節點啓動默認是Follower,同時會給每個Follower一個elect timeout(100ms~300ms)的一個隨機值,哪個節點超時時間到就轉變爲Candidate 狀態(可能有多個參選者),

Candidate 狀態的節點緊接着會發起投票請求,會有如下兩種狀態變化:

  • 如果收到的投票數達到半數以上,即成爲新的Leader

  • 反之如果別的Candidate當選Leader,則此Candidate則置爲Follow

Leader如果發現有比自己任期更高的Leader,則降爲Follower角色。

 

  • 在對外正常提供服務的時候只有Leader和Follower兩種狀態;在選舉過程中,有Candidate和Follower兩種狀態。

  • Follower收到心跳或者投票請求,則重新開始計時

  • 只有在重新選舉或者初始化的時候會範圍隨機設定這個timeout時間,在其他時候這個隨機值並不改變。

 

2.1.2 選舉細節

2.1.2.1 數據結構與通信協議

在所有節點持久存在的:(在響應遠程過程調用 RPC 之前穩定存儲的)

名稱

描述

currentTerm

服務器最後知道的任期號(從 0 開始遞增)

votedFor

在當前任期內收到選票的Candidate Id(如果沒有就爲 null)

log[]

日誌條目;每個條目包含狀態機的要執行命令和從Leader處收到日誌時的任期號

 

在所有節點上不穩定存在的:

名稱

描述

commitIndex

已知的被提交的最大日誌條目的索引值(從 0 開始遞增)

lastApplied

被狀態機執行的最大日誌條目的索引值(從 0 開始遞增)

在Leader節點上不穩定存在的:(在選舉之後初始化的)

名稱

描述

nextIndex[]

對於每一個服務器,記錄需要發給它的下一個日誌條目的索引(初始化爲Leader上一條日誌的索引值 +1)

matchIndex[]

對於每一個服務器,記錄已經複製到該服務器的日誌的最高索引值(從 0 開始遞增)

 

在整個term只有兩種RPC請求:

功能

調用者

參數

參數值

接受者實現邏輯

返回值

返回內容

RequestVote

Candidate

term

Candidate的任期號

  1. 如果term < currentTerm返回 false

  2. 如果votedFor爲空或者與candidateId相同,並且候選人的日誌和自己的日誌一樣新,則給該候選人投票

term

任期號

candidateId

請求投票的Candidate id

success

如果其它服務器包含能夠匹配上 prevLogIndex 和 prevLogTerm 的日誌時爲真

lastLogIndex

Candidate最新日誌條目的索引值

 

 

lastLogTerm

Candidate最新日誌條目對應的任期號

 

 

AppendEntries

Leader

term

Candidate的任期號

  1. 如果 term < currentTerm返回 false

  2. 如果在prevLogIndex處的日誌的任期號與prevLogTerm不匹配時,返回 false

  3. 如果一條已經存在的日誌與新的衝突(index 相同但是任期號 term 不同),則刪除已經存在的日誌和它之後所有的日誌

  4. 添加任何在已有的日誌中不存在的條目

  5. 如果leaderCommit > commitIndex,將commitIndex設置爲leaderCommit和最新日誌條目索引號中較小的一個

term

目前的任期號,用於Candidate更新自己

leaderId

Leader的 id,爲了其他服務器能重定向到客戶端

voteGranted

如果Candidate收到選票爲 true

prevLogIndex

Candidate最新日誌條目的索引值

 

 

prevLogTerm

Candidate最新日誌條目對應的任期號

 

 

entries[]

將要存儲的日誌條目(表示 heartbeat 時爲空,有時會爲了效率發送超過一條)

 

 

leaderCommit

Leader提交的日誌條目索引值

 

 

 

 

2.1.2.2 投票細節

以上對選出過程做了簡要描述,但是對細節沒有涉及,我們很明顯有以下疑問:

同時發起投票請求?

在自己成爲Candidate的情況下,收到請求怎麼辦?

在節點已經成爲Leader的情況下,收到投票請求怎麼處理?

一個節點會不會投出多張票?

 

Raft的投票機制詳細過程:

  1. follower遞增自己的term。

  2. follower將自己的狀態變爲candidate。

  3. 投票給自己。

  4. 向集羣其它機器發起投票請求(RequestVote請求)。

  5. 當以下情況發生,結束自己的Candidate狀態。

    1. 超過集羣一半服務器都同意,狀態變爲leader,並且立即向所有服務器發送心跳消息,之後按照心跳間隔時間發送心跳消息。任意一個term中的任意一個服務器只能投一次票,所有的candidate在此term已經投給了自己,那麼需要另外的follower投票才能贏得選舉。

    2. 在等待期間,發現了其它leader並且這個leader的term不小於自己的term,狀態轉爲follower。否則丟棄消息。

    3. 沒有服務器贏得選舉,可能是由於網絡超時或者服務器原因沒有leader被選舉,這種情況比較簡單,超時之後重試。有一種情況被稱爲split votes,比如一個有三個服務器的集羣中所有服務器同時發起選舉,那麼就不可能有leader被選舉出來,此時如果超時之後重試很可能所有服務器又同時發起選舉,這樣永遠不可能有leader被選舉出來。Raft處理這種情況是採用上文提到過的random election timeout,隨機超時保證了split votes發生的機率很小。

 

收到投票請求的響應邏輯:

  1. 如果term < currentTerm返回 false(5.1 節)

  2. 如果votedFor爲空或者與candidateId相同,並且Candidate的日誌和自己的日誌一樣新,則給該Candidate投票(5.2 節 和 5.4 節

 

 

如下圖所示,初始時,所有節點都是term=0;現假設同時A和C同時成爲Candidate,發起投票請求(其中附term),B和D關於同一個term投票請求(B本地能做到只處理一個請求)只會投出去一票。

採用了term機制來保證了“一人一票”,在此規則下只會出現如下兩種結果之一:

  • 其中一個超過半票,一個沒有,這種超過半票的順利當選

  • 如果沒有任何Candidate當選Leader,會重走選舉流程。

 

 

 

 

2.1.3 實例分析-異常情況

Follow節點之間的“失聯”沒有關係。

異常情況1:

如下圖所示:Leader出了異常(假如當前集羣的term是3),沒有發心跳給FA、FB、FC,這三者就會如上述章節所述,進行選舉,假如選出的新Leader是FA,那麼FA(term=4),發起的選舉是關於term=4選舉,選舉成功後,整個集羣(不包括失聯的前Leader D) Leader是A。

如果一段時間之後,D節點恢復,和其他節點成功連接,此時,D發現集羣內已經有了其他Leader,term比自己高,則將自己的角色修改爲Follow,從新Leader同步term和log。

 

 

異常情況2:

 

比如C和Leader之間網絡斷開,超過心跳間隔沒有收到來自Leader D的心跳包,elect timeout時間到了,C進入Candidate角色,發起關於term=4(原term=3)選舉。按照論文描述,

  • A和B收到C的term比自身大(term=3),而且有比C領先的日誌,則投票結果是拒絕。此時C一直收不到D的心跳,導致C term會一直增大發起選舉。針對這個問題的解決方案是PreVote。

  • A和B收到C的term比自身大(term=3),而且沒有比C領先的日誌(C斷了期間沒有日誌更新),此時會投票給C,Leader易主,換爲C。因爲日誌一樣,此時C還沒有成爲Leader也不會有新日誌,易主成本不大。

 

這種情況還有一個變種,C和其他節點全部失聯,此時C會一直增加自己的term,這種情況也類似,據說有個長篇論文。pre-candidate

 

其他的一些異常分析:

網絡分區,term一直增大,反覆選舉https://www.zhihu.com/question/302761390

從異常處理看Raft協議:https://zhuanlan.zhihu.com/p/64405742

 

2.1.4 選舉問題分析

1 奇數問題

集羣到底是否是必須是奇數,是否推薦使用奇數。

  1. 沒有絕對必要使用奇數,其實使用偶數也可以

  2. 選用奇數,是因爲在同樣容錯下,奇數和偶數都是可以的(5個Node容忍2個失敗,6個還是容忍兩個失敗),但是從節省資源角度來說,選用奇數合理;

  3. 同時選用奇數可以在一定程度上避免"平票的情況"。大部分情況下在某個時刻還是一個節點壞,此時集羣剩餘的就是奇數,選舉很容易選出Leader

 

2 網絡抖動是否會引發選舉

論文中對接受到請求的節點的響應實現邏輯做出如下描述:

  1. 如果term < currentTerm返回 false(5.1 節)

  2. 如果votedFor爲空或者與candidateId相同,並且Candidate的日誌和自己的日誌一樣新,則給該Candidate投票(5.2 節 和 5.4 節)

 

按照這個邏輯,在2.1.2小節中示例的異常情況,則C發起選舉併成爲Leader,那麼會不會網絡抖動一下導致某個節點和Leader失聯就會Leader易主。

在論文中另外有段關於心跳時間和elect timeout的說法有要求,

  1. broadcastTime指的是一臺服務器並行的向集羣中的其他服務器發送 RPC 並且收到它們的響應的平均時間

  2. broadcastTime << electionTimeout << MTBF

  3. broadcastTime和MTBF是由系統決定的性質,但是electionTimeout是我們必須做出選擇的。Raft 的 RPC 需要接收方將信息持久化的保存到穩定存儲中去,所以廣播時間大約是 0.5 毫秒到 20 毫秒,這取決於存儲的技術。因此,electionTimeout一般在 10ms 到 500ms 之間。大多數的服務器的MTBF都在幾個月甚至更長,很容易滿足這個時序需求。

 

這裏建議的elect timeout比心跳時間大了好多個量級,所以在elect timeout中,有很多次發送心跳的機會。所以並不會因爲網絡抖動而造成Leader易主,但是如果C到D節點之間的通信線路的確出問題了,長時間出問題的確會發生Leader易主了。但是從合理性來說,此時A和B還是知道原Leader的存在,並且發起投票的C節點信息並不領先於D,此時A和B應該拒絕投票給C才合理(據說有些工程就是這樣實現的,沒有驗證)。

 

3 心跳超時

在Leader成爲網絡孤島時,Leader可以發出心跳、Follower可以收到心跳但是Leader收不到心跳回應,這種情況下Leader此時已經出現網絡異常,但是由於一直可以向外發送心跳包會導致Follower無法切換狀態進行選取,系統陷入停滯。爲了避免第二種情況發生,模塊中設置了心跳超時機制,Leader每次收到心跳回應時會進行相應記錄,一旦一段時間後記錄沒有更新則Leader放棄Leader身份並轉換爲Follower節點。

 

4 Leader性能瓶頸

所有客戶端的讀寫請求都轉發到Leader上?

是的,可以請求任意節點,但是都會轉發到Leader節點

比如Consul,就是所有的請求都會有Server達到Leader(client只會轉發)。Client知道有哪些Server,依靠的是gossip協議

讀寫請求全部壓力都在Leader帶上?

是的,讀直接讀Leader的本地內容,寫的話需要日誌提交

 

讀寫都在Leader上,很容易出現性能瓶頸?

  • 所有讀寫必須經過Leader這種機制是對Leader功能的強化,非常有效的簡化了整個協議

  • 但是也使得Raft協議的Leader存在着性能瓶頸。

 

  • 如果讀請求不最終轉發到Leader,比如請求打到一個沒有生效的網絡分區,讀取的內容低於最新內容。讀了髒數據,stale read問題。

  • 國內百度和阿里實現的Raft都有着自己的優化。

 

5 網絡分區

其實異常情況1已經是一個異常分區了。異常分區有兩種,一種是原Leader在大數的一側;另一種是原Leader在少數一側。

  • 當發生網絡分區的時候,在不同分區的節點接收不到leader的心跳,則會開啓一輪選舉,形成不同leader的多個分區集羣。

  • 當客戶端給不同leader的發送更新消息時,不同分區集羣中的節點個數小於原先集羣的一半時,更新不會被提交,而節點個數大於集羣數一半時,更新會被提交。

  • 當網絡分區恢復後,被提交的更新會同步到其他的節點上,其他節點未提交的日誌會被回滾並匹配新leader的日誌,保證全局的數據是一致的

 

 

2.2 日誌複製

2.2.1 日誌複製原理

2.2.1.1 複製狀態機及日誌結構

相同的初識狀態 + 相同的輸入 = 相同的結束狀態

論文中有一個很重要的詞deterministic,就是說不同節點要以相同且確定性的函數來處理輸入,而不要引入一下不確定的值,比如本地時間等。如何保證所有節點 輸入相同輸出相同,使用replicated log是一個很好的方法,log具有持久化、保序的特點,是大多數分佈式系統的基石。

因此,可以這麼說,在raft中,leader將客戶端請求(command)封裝到一個個log entry,將這些log entries複製(replicate)到所有follower節點,然後大家按相同順序應用(apply)log entry中的command,則狀態肯定是一致的。

複製狀態機

 

 

日誌結構

 

 

2.2.1.2 日誌複製基本流程

1)Client向Leader提交指令(如:SET 5),Leader收到命令後,將命令追加到本地日誌中。此時,這個命令處於“uncomitted”狀態,複製狀態機不會執行該命令。

 

(2)然後,Leader將命令(SET 5)併發複製給其他節點,並等待其他其他節點將命令寫入到日誌中,如果此時有些節點失敗或者比較慢,Leader節點會一直重試,知道所有節點都保存了命令到日誌中。之後Leader節點就提交命令(即被狀態機執行命令,這裏是:SET 5),並將結果返回給Client節點。

 

 

(3)Leader節點在提交命令後,下一次的心跳包中就帶有通知其他節點提交命令的消息,其他節點收到Leader的消息後,就將命令應用到狀態機中(State Machine),最終每個節點的日誌都保持了一致性。

 

Leader節點會記錄已經交的最大日誌index,之後後續的heartbeat和日誌複製請求(Append Entries)都會帶上這個值,這樣其他節點就知道哪些命令已經提交了,就可以讓狀態機(State  Machine)執行日誌中的命令,使得所有節點的狀態機數據都保持一致。

 

 

 

就A和D倆看,在A複製第一條指令之前,

A中關於D的記錄: nextIndex:1 / matchIndex=0,在給D發送了複製請求(複製請求中LeaderCommitedIndex=0)之後,D收到請求之後(由於收到A的LeaderCommitedIndex=0,不會有任何移動本機commitedIndex的動作)給了A響應,

Leader A收到響應之後,準備下次發送2條日誌給D,則修改關於D的記錄:nextIndex:2 / matchIndex=1。--> 然後開發發送第2、3個日誌(由於D網絡不好,響應慢,在此過程中A的commitedIndex已經到了5),在發送該第2個複製指令的時候帶上LeaderCommitedIndex=5,D在收到該複製指令後,複製2條日誌(此時總有三條了),然後設置本地commitedIndex=3

另外一方面,Leader通過matchIndex發現index=1的log的複製請求已經得到了大部分迴應,下一次心跳帶上LeaderCommitedIndex,讓Follow的commit和Leader同步。如果該Commit發送到Follow失敗也沒有關係,失敗意味着Follow的commit落後於Leader,會在後面根於下面這個規則同步上。

如果leaderCommit > commitIndex,將commitIndex設置爲leaderCommit和最新日誌條目索引號中較小的一個

 

還有一種情況是D已經追評了A的日誌,兩者都已經commit=8,此時Leader收到請求9,然後發出複製請求(LeaderCommitedIndex=8),然後D響應請求(不會修改CommitedIndex值)表示已經複製,A收到響應修改matchIndex和NextIndex,另外A發現得到了大多數響應,會在下一次心跳包中帶上commit請求,讓Follow修改commit值。

2.2.1.3 一致性檢查

Raft日誌同步保證如下兩點:

  • 如果不同日誌中的兩個條目有着相同的索引和任期號,則它們所存儲的命令是相同的。

  • 如果不同日誌中的兩個條目有着相同的索引和任期號,則它們之前的所有條目都是完全一樣的。

第一條特性源於Leader在一個term內在給定的一個log index最多創建一條日誌條目,同時該條目在日誌中的位置也從來不會改變。

第二條特性源於 AppendEntries 的一個簡單的一致性檢查:當發送一個 AppendEntries RPC 時,Leader會把新日誌條目緊接着之前的條目的log index和term都包含在裏面。如果Follower沒有在它的日誌中找到log index和term都相同的日誌,它就會拒絕新的日誌條目。

一般情況下,Leader和Followers的日誌保持一致,因此 AppendEntries 一致性檢查通常不會失敗。然而,Leader崩潰可能會導致日誌不一致:舊的Leader可能沒有完全複製完日誌中的所有條目。

 

上圖闡述了一些Followers可能和新的Leader日誌不同的情況。一個Follower可能會丟失掉Leader上的一些條目,也有可能包含一些Leader沒有的條目,也有可能兩者都會發生。丟失的或者多出來的條目可能會持續多個任期。

 

比如上述的a,append時候一致性檢查,一致點就在當前點,直接append;比如B一致性檢查一致點在index=4的位置,則Leader從4開始複製日誌給b。

比如d,一直點在index=10,從index=10開始複製。

 

Leader通過強制Followers複製它的日誌來處理日誌的不一致,Followers上的不一致的日誌會被Leader的日誌覆蓋。

Leader爲了使Followers的日誌同自己的一致,Leader需要找到Followers同它的日誌一致的地方,然後覆蓋Followers在該位置之後的條目。

Leader會從後往前試,每次AppendEntries失敗後嘗試前一個日誌條目,直到成功找到每個Follower的日誌一致位點,然後向後逐條覆蓋Followers在該位置之後的條目。

 

2.2.2 日誌複製異常分析

  • 不管是Follow的日誌多餘、少於、差異於Leader,都是以Leader爲準,進行修復。

  • 原Leader日誌領先於大多數Follow(比如Leader發出日誌複製命令A 之後就掛了),但是Candidate的日誌和其他Follow是一樣的,這種情況下Candidate當選爲新Leader,該日誌少於原Leader,原Leader收到的客戶端請求A就作廢了嗎?

 

 

2.2.3 日誌複製問題記錄

  1. 爲什麼不一次請求,直接定位到相同日誌;而是不同往前嘗試。

  2. Leader轉化的時候的日誌怎麼處理,是否會丟失。

3 如果在日誌複製的過程中Leader掛了怎麼辦?

4 在Follower已經ack AppendEntities之後,但是還是處於uncommited狀態的時候Follower掛了怎麼辦?

 

2.3 成員變更

在實際業務場景中,我們會經常更改節點配置。例如更改日誌級別。雖然通過關閉整個集羣,升級配置文件,然後重啓整個集羣也可以解決這個問題,但是這會導致在更改配置的過程中,整個集羣不可用。

另外,如果存在需要手工操作,那麼就會有操作失誤的風險。爲了避免這些問題, Raft 一致性算法中設計了一套自動改變配置並能保證系統一致性的機制。

 

3 Consul與Raft

Consul使用Serf(基於goisp,https://www.serf.io/)來管理節點,每個節點上都會有一份成員列表。

Gossip協議已經是P2P網絡中比較成熟的協議了。Gossip協議的最大的好處是,即使集羣節點的數量增加,每個節點的負載也不會增加很多,幾乎是恆定的。這就允許Consul管理的集羣規模能橫向擴展到數千個節點。

Consul的每個Agent會利用Gossip協議互相檢查在線狀態,本質上是節點之間互Ping,分擔了服務器節點的心跳壓力。如果有節點掉線,不用服務器節點檢查,其他普通節點會發現,然後用Gossip廣播給整個集羣。

 

在此基礎上,使用Raft協議來保證整個系統的一致性。

Consul通過serf知道整個集羣有多少個節點,每次添加一個節點之後,就會檢查節點數是否到了bootstrap expect配置的數量。如果到了開始引導 --> 啓動Raft選舉定時器,爲每一個節點範圍隨機賦予elect timeout。然後就進入Raft的選舉過程。

集羣初次啓動只有Consul集羣的節點數量到達了bootstrap expect數,纔會開始進行選舉過程。

 

只有一個節點:

 

 

 

如下圖,增加了一個節點,serf發現節點,開始觸發MemberJoin事件。

記錄下了第一次的節點列表,嘗試去連接第一次的列表。 如果是第一次是隻有達到3個纔開始選舉。

 

 

 

0 參考資料

[官方演示器] https://raft.github.io/

[動畫, 簡明易懂] http://thesecretlivesofdata.com/raft/

[raft論文的中文版] https://github.com/maemual/raft-zh_cn || https://linux-network-programming.readthedocs.io/zh_CN/latest/translations/raft-paper.html

[raft詳解]http://www.solinx.co/archives/415

[一致性詳解] https://zhuanlan.zhihu.com/p/67949045

[PreVote] https://www.jianshu.com/p/1496228df9a9

[Follow失聯] https://www.zhihu.com/question/329076128

[Raft客戶端] https://juejin.im/post/5af14cd2f265da0b863633e4

[stale read] https://www.cnblogs.com/williamjie/p/11137118.html

[gossip] https://toutiao.io/posts/0syf8m/preview

[Consul原理]http://ljchen.net/2019/01/04/consul%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90/

[在各種Failure情況下如何達成一致,有非常詳盡的分析]http://zenlife.tk/raft-fault-tolerance.md

[Raft及共識算法] http://tinylcy.me/2018/Understanding-the-Raft-consensus-algorithm-One/

[Raft實現小結] https://feilengcui008.github.io/post/raft%E5%AE%9E%E7%8E%B0%E5%B0%8F%E7%BB%93/

[日誌複製] https://bloodhunter.github.io/2019/03/31/raft-xie-yi-zhi-ri-zhi-fu-zhi/

[Raft協議方面的疑問] https://www.zhihu.com/question/54997169

[實現思路] http://atomicer.cn/2019/05/17/etcd-raft%E4%B8%ADraft%E7%AE%97%E6%B3%95%E7%9A%84%E5%AE%9E%E7%8E%B0%E6%80%9D%E8%B7%AF%E5%8F%82%E8%80%83/

[細節理解] https://www.jianshu.com/p/80fb90fff5ba

[深入共識算法] https://shuwoom.com/?p=826

發佈了87 篇原創文章 · 獲贊 20 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章