Raft 可能你們對其還有點陌生,但我相信你們都知道 Paxos。但 Paxos 很被理解,反正我如今也不懂。兩位研究者也提到,他們也花了很長的時間來理解 Paxos,他們也以爲很難理解,因而研究出了 Raft 算法。html
Raft 是工程上使用較爲普遍的強一致性、去中心化、高可用的分佈式協議。接下來,我就帶你們輕鬆瞭解 Raft 核心世界。算法
當啓動集羣 A、B、C 三個節點時,三個節點都處於 Follower 狀態中,在心跳超時時間內沒有收到 Leader 節點的信息,某一個節點優先轉入 Candidate 狀態,併發起一個投票請求,這裏假設是 A 節點,A 在發起投票請求以前會先投一票給本身,若是 B 和 C 在收到請求的時候,還處於 election time out ,會直接投給 A ,A 就成爲了 Leader 節點,並通知其餘節點本身當選,並維護心跳。網絡
以上是比較理想狀況下的選舉過程,咱們先提煉一下關鍵信息:併發
Raft 集羣各個節點之間是經過 RPC 通信傳遞消息的,每一個節點都包含一個RPC 服務端與客戶端,初始時啓動 RPC 服務端、狀態設置爲 Follower、啓動選舉定時器,每一個 Raft 節點的選舉定時器超時時間都在 100-500 毫秒之間且並不一致。app
處於 Candidate 狀態的節點會發起一個投票請求,請求內容:候選人任期(term)、候選人ID(candidateId)、日誌項索引(lastLogIndex)、日誌項任期(lastLogTerm)。響應內容:當前任期(term)、投票結果(voteGranted)。每一個任期內,每一個 Raft 節點都只能投票一次。分佈式
假設 A(Term=1) 發起投票請求時,B(Term=1) 也發起了投票請求(此時B尚未收到A的請求),若是 A 先請求到 C 並及時響應,那麼 A(Term=1)。若是出現票數同樣的狀況,超過選舉定時器超時時間,節點進行下一輪的投票請求(Term 加 1)。spa
如何保證選舉票數存在相同的狀況(腦裂)?
選舉定時器超時時間不一樣節點不一致
Raft 集羣節點數設爲奇數日誌
心跳超時時間與選舉超時時間怎麼定?
當 Follower 節點收到 Leader 節點心跳信息時,會重置選舉超時時間,於是,心跳時間應該小於選舉時間。htm
A 能得到 C 的票的前提?blog
當 Leader 被選舉出來以後,由 Leader 處理來自客戶端的請求,Leader 會對併發處理進行排序,並將這些請求的排序和信息經過心跳的方式傳遞到 Follower 節點。
完整流程:
Log entry
在 Raft 中,Leader 將客戶端請求(Command)封裝到一個個 Log Entry,並將 Log Entry 按與 Leader 中存儲的前後順序同步到 Follower 節點。
從上圖中能夠看出,Logs 順序排列的 Log Entry 組成 ,每一個 Log Entry 除了包含 Command,還包含產生該 Log Entry 時的 Leader Term。從上圖能夠看到,5 個節點的日誌並不徹底一致,Raft 算法爲了保證高可用,並非強一致性,而是最終一致性,Leader 會不斷嘗試給 Follower 發 Log Entries,直到全部節點的 Log Entries 都相同。
在上面的流程中,Leader 只須要 Log Entry 被複制到大多數節點便可向客戶端返回,一旦向客戶端返回成功消息,那麼系統就必須保證 Log Entry(實際上是 Log 所包含的 Command )在任何異常的狀況下都不會發生回滾,即:當前 Log Entry 處於 Commited 狀態了。
正常狀況下,一切都是沒有問題的,但存在網絡問題、Leader 選舉等狀況從而存在 Follower 與 Leader 之間的數據不一致性。在 Raft 中,一切根據 Leader 數據進行覆蓋,由於 Leader 必定包含最新的 Committed Log,這裏注意是 Committed Log,也就是說已經被絕大多節點所複製了確認的,不能回滾的日誌數據。
其過程是 A 節點收到 Leader 的請求後,對比 Leader 節點記錄的上一個日誌記錄的 index 和 term,發現本身的日誌中不存在這個命令,因而拒絕這個請求。此時,Leader 節點知道發生了不一致,因而遞減 nextIndex,並從新給A節點發送日誌複製請求,直到找到日誌一致的地方爲止。而後把 Follower 節點的日誌覆蓋爲 Leader 節點的日誌內容。
爲何 Leader 具備最新的 committed log?
Raft 在選舉的過程當中,就存在一個校驗項,當選 Leader 的節點 commited 日誌數據不能舊於其餘節點。
在場景 c 中,當前 Leader 爲 S1,最新的 log entry 是 4,此時 raft 算法會將最新的 4 的數據同步到各個節點上,順帶對缺失 2 數據信息進行補充,這裏要注意是順帶哦,而不是先同步 2,在同步 4。若是 2 數據絕大多數節點都存在了,就能夠處於 commited 狀態,響應客戶端請求,再也不容許回滾。
若是 Leader 節點獲取大多數的節點的贊成,但不一樣意的節點上存在 log 數據是 Leader 節點所沒有的數據呢?
Leader 節點的數據會覆蓋該節點的數據。
若是 leader 收不到majority節點的消息呢?
Leader 能夠本身 step down,自行轉換到 follower 狀態。
Leader 選舉:
一個節點獲得 majority 的投票才能成爲 leader,而節點 A 給節點 B 投票的其中一個前提是,B 的日誌不能比 A 的日誌舊。
觸發選舉條件:心跳超時時間內沒有收到 Leader 節點的心跳。
當選 Leader 條件:得到最多票數的節點當選。
心跳時間應該小於選舉時間。
Log Replication 約束:
一個 Log 被複制到大多數節點,就是 Committed,保證不會回滾。
Leader 必定包含最新的 Committed Log所以 Leader 只會追加日誌,不會刪除覆蓋日誌。
不一樣節點,某個位置上日誌相同,那麼這個位置以前的全部日誌必定是相同的。
Log 數據只容許追加,不容許刪除和修改。
參考:
關注個人公衆號,能得到第一手的分享內容哦!