天天看點

白話-raft協定(一)前言1 初識2 上司者選舉3日志同步3.1 小黃和小藍的回應MsgAppResp3.2 小紅确認日志記錄,繼續發送MsgApp3.3 小黃和小藍确認日志記錄3.4 小紅的收尾

前言

下面文章會以圖形方式來解讀raft協定,與其他作者文檔相比,會更偏向工程的實作細節

适合讀者:

  • 想了解raft協定的懶人,不想讀論文,不想看代碼,不想動腦袋。。。

對一般人而言,了解raft協定,

https://raft.github.io/

這個網站都會接觸到,它提供了:

動畫部分建議先了解下,有助于下面的學習。

下面的raft流程互動和參數說明參考了etcd中的raft實作

1 初識

19世紀80年代,小紅(id=1)、小黃(id=2)、小藍(id=3)三位同學商量放假去哪兒玩,她們之間商議過程隻能通過書信(會發生各種意外情況導緻信件丢失或者回複緩慢)。我們一起看看三人之間是如何達成一緻意見的。

先熟悉第一個概念,角色。每位同學都會分屬下面三種角色之一:

角色 英文
上司者 leader
跟随者 follower
候選者 candidate

故事開頭,每個同學都是follower角色

2 上司者選舉

2.1 選舉逾時時間 election timeout和任期term

既然是商量事情,總有一個要先提意見的,為了公平起見,給每位同學一個随機的逾時時間(election timeout),誰先過了逾時時間就準備開始發言

白話-raft協定(一)前言1 初識2 上司者選舉3日志同步3.1 小黃和小藍的回應MsgAppResp3.2 小紅确認日志記錄,繼續發送MsgApp3.3 小黃和小藍确認日志記錄3.4 小紅的收尾

圖中,小紅150mm時間最短,小紅最先逾時

與逾時時間類似,每位同學都有一個任期屬性,正常情況下每發起一次選舉,任期會自動加1,初始狀态大家的任期都是0,圖中的其他屬性暫時忽略

2.2 小紅的自我投票(MsgHup)和投票請求(MsgVote)

2.1節中小紅最先到達逾時時間,她的動作如下所示:

白話-raft協定(一)前言1 初識2 上司者選舉3日志同步3.1 小黃和小藍的回應MsgAppResp3.2 小紅确認日志記錄,繼續發送MsgApp3.3 小黃和小藍确認日志記錄3.4 小紅的收尾
  1. 小紅首先給自己發了一個Message1,type為MsgHup,告知自己要參與選舉了
  2. 小紅收到Message1後,将自己的term由0改為1,狀态由StateFollower改為了StateCandidate,至此角色由follower轉換為了candidate,順便給自己投了一票(votes[1]=ture)
  3. 小紅在term為1的任期内正式向小黃和小藍發起投票請求(Message2.1和Message2.2) ,type為MsgVote

2.3 小黃和小藍的回複(MsgVoteResp)

先看小黃的回複:

白話-raft協定(一)前言1 初識2 上司者選舉3日志同步3.1 小黃和小藍的回應MsgAppResp3.2 小紅确認日志記錄,繼續發送MsgApp3.3 小黃和小藍确認日志記錄3.4 小紅的收尾
  1. 小黃接收到Message2.1後,将Message2.1的term(1)與自身的term(虛線框0)比較,發現自身的term小于Message2.1,繼續保持自己的follower角色,同時将自身的term改為1
  2. 小黃向小紅發送Message3.1進行回複,type為MsgVoteResp

小藍的回複與小黃類似,回複Message3.2,見下圖,不再贅述:

白話-raft協定(一)前言1 初識2 上司者選舉3日志同步3.1 小黃和小藍的回應MsgAppResp3.2 小紅确認日志記錄,繼續發送MsgApp3.3 小黃和小藍确認日志記錄3.4 小紅的收尾

2.4 小紅變為了leader

白話-raft協定(一)前言1 初識2 上司者選舉3日志同步3.1 小黃和小藍的回應MsgAppResp3.2 小紅确認日志記錄,繼續發送MsgApp3.3 小黃和小藍确認日志記錄3.4 小紅的收尾
  1. 小紅先收到了小黃的Message3.1,type為MsgVoteResp。這時候小紅已經獲得了兩票,一票是自己投自己,一票是小黃投的(對應圖中的votes[i]變量,votes[1]=ture,votes[2]=true),小紅得票已經超過叢集的半數,由此小紅的狀态從StateCadidate轉變為了StateLeader
  2. 接着小紅給自己建立了一個空日志條目,開始向小黃和小藍發送Message4.1和Message4.2,type為MsgApp,即要求follower同步自己的資料
  3. 小紅的prs[1].match_=1

小紅收到了小黃的Message3.1後,由于滿足半數投票,已經變為了leader角色,這時再收到小藍的Message3.2,不再需要做任何操作

這時,小紅在本地記錄了一個空的Entry

白話-raft協定(一)前言1 初識2 上司者選舉3日志同步3.1 小黃和小藍的回應MsgAppResp3.2 小紅确認日志記錄,繼續發送MsgApp3.3 小黃和小藍确認日志記錄3.4 小紅的收尾
  • 此時的Entry隻是臨時記錄,是以為虛線

3日志同步

3.1 小黃和小藍的回應MsgAppResp

2.4節小紅開始向小黃和小藍發送Message4.1和Message4.2,下面是小黃和小藍收到後的回複

白話-raft協定(一)前言1 初識2 上司者選舉3日志同步3.1 小黃和小藍的回應MsgAppResp3.2 小紅确認日志記錄,繼續發送MsgApp3.3 小黃和小藍确認日志記錄3.4 小紅的收尾
  • 小黃和小藍收到資訊後,各自也準備了一個空的Entry,并且向小紅回複了type為MsgAppResp的Mesaage(Message5.1和Message5.2)

此時,三位同學的日志狀态如下:

白話-raft協定(一)前言1 初識2 上司者選舉3日志同步3.1 小黃和小藍的回應MsgAppResp3.2 小紅确認日志記錄,繼續發送MsgApp3.3 小黃和小藍确認日志記錄3.4 小紅的收尾

3.2 小紅确認日志記錄,繼續發送MsgApp

白話-raft協定(一)前言1 初識2 上司者選舉3日志同步3.1 小黃和小藍的回應MsgAppResp3.2 小紅确認日志記錄,繼續發送MsgApp3.3 小黃和小藍确認日志記錄3.4 小紅的收尾
  • 小紅收到小黃的Message5.1後,會設定prs[2].match_=1,至此已經有半數以上(2個人)同意進行日志送出,是以小紅将自身的raftLog.committed_由0設定為1
  • 小紅處理完Message5.1後,會繼續向小黃發送Message6.1,type為MsgApp,繼續同步日志記錄。與Message4.1不同的是,此時index、logterm、commit由0變為了1
  • 小紅繼續受到小藍的Message5.2,會設定prs[3].match_=1,處理完後同樣會發送Message6.2給小藍,index、logterm、commit同樣為1

此時日志狀态,小紅的日志由虛線變為實線

白話-raft協定(一)前言1 初識2 上司者選舉3日志同步3.1 小黃和小藍的回應MsgAppResp3.2 小紅确認日志記錄,繼續發送MsgApp3.3 小黃和小藍确認日志記錄3.4 小紅的收尾

3.3 小黃和小藍确認日志記錄

白話-raft協定(一)前言1 初識2 上司者選舉3日志同步3.1 小黃和小藍的回應MsgAppResp3.2 小紅确認日志記錄,繼續發送MsgApp3.3 小黃和小藍确認日志記錄3.4 小紅的收尾
  1. 小黃收到小紅Message6.1後,根據msg中的commit為1,修改自己的commit為1,然後發送type為MsgAppResp的Message7.1
  2. 同理,小藍也會修改自己的commit為1,然後傳回type為MsgAppResp的Message7.2

此時日志狀态,小藍和小黃由虛線變為實線

白話-raft協定(一)前言1 初識2 上司者選舉3日志同步3.1 小黃和小藍的回應MsgAppResp3.2 小紅确認日志記錄,繼續發送MsgApp3.3 小黃和小藍确認日志記錄3.4 小紅的收尾

3.4 小紅的收尾

  1. 當小紅收到Message7.1後,檢查msg中的index和本地的prs[2].match_,兩者相等,不做任何操作
  2. 同理,小紅收到Message7.2後,檢查msg中的index和本地的prs[3].match_,兩者相等,不做任何操作

繼續閱讀