前言
下面文章會以圖形方式來解讀raft協定,與其他作者文檔相比,會更偏向工程的實作細節
适合讀者:
- 想了解raft協定的懶人,不想讀論文,不想看代碼,不想動腦袋。。。
對一般人而言,了解raft協定,
https://raft.github.io/這個網站都會接觸到,它提供了:
- raft協定論文: https://raft.github.io/raft.pdf
- raft協定動畫示範: http://thesecretlivesofdata.com/raft/
- raft協定代碼實作:網站提供了git倉庫位址,知名的如etcd/raft
動畫部分建議先了解下,有助于下面的學習。
下面的raft流程互動和參數說明參考了etcd中的raft實作
1 初識
19世紀80年代,小紅(id=1)、小黃(id=2)、小藍(id=3)三位同學商量放假去哪兒玩,她們之間商議過程隻能通過書信(會發生各種意外情況導緻信件丢失或者回複緩慢)。我們一起看看三人之間是如何達成一緻意見的。
先熟悉第一個概念,角色。每位同學都會分屬下面三種角色之一:
角色 | 英文 |
---|---|
上司者 | leader |
跟随者 | follower |
候選者 | candidate |
故事開頭,每個同學都是follower角色
2 上司者選舉
2.1 選舉逾時時間 election timeout和任期term
既然是商量事情,總有一個要先提意見的,為了公平起見,給每位同學一個随機的逾時時間(election timeout),誰先過了逾時時間就準備開始發言

圖中,小紅150mm時間最短,小紅最先逾時
與逾時時間類似,每位同學都有一個任期屬性,正常情況下每發起一次選舉,任期會自動加1,初始狀态大家的任期都是0,圖中的其他屬性暫時忽略
2.2 小紅的自我投票(MsgHup)和投票請求(MsgVote)
2.1節中小紅最先到達逾時時間,她的動作如下所示:
- 小紅首先給自己發了一個Message1,type為MsgHup,告知自己要參與選舉了
- 小紅收到Message1後,将自己的term由0改為1,狀态由StateFollower改為了StateCandidate,至此角色由follower轉換為了candidate,順便給自己投了一票(votes[1]=ture)
- 小紅在term為1的任期内正式向小黃和小藍發起投票請求(Message2.1和Message2.2) ,type為MsgVote
2.3 小黃和小藍的回複(MsgVoteResp)
先看小黃的回複:
- 小黃接收到Message2.1後,将Message2.1的term(1)與自身的term(虛線框0)比較,發現自身的term小于Message2.1,繼續保持自己的follower角色,同時将自身的term改為1
- 小黃向小紅發送Message3.1進行回複,type為MsgVoteResp
小藍的回複與小黃類似,回複Message3.2,見下圖,不再贅述:
2.4 小紅變為了leader
- 小紅先收到了小黃的Message3.1,type為MsgVoteResp。這時候小紅已經獲得了兩票,一票是自己投自己,一票是小黃投的(對應圖中的votes[i]變量,votes[1]=ture,votes[2]=true),小紅得票已經超過叢集的半數,由此小紅的狀态從StateCadidate轉變為了StateLeader
- 接着小紅給自己建立了一個空日志條目,開始向小黃和小藍發送Message4.1和Message4.2,type為MsgApp,即要求follower同步自己的資料
- 小紅的prs[1].match_=1
小紅收到了小黃的Message3.1後,由于滿足半數投票,已經變為了leader角色,這時再收到小藍的Message3.2,不再需要做任何操作
這時,小紅在本地記錄了一個空的Entry
- 此時的Entry隻是臨時記錄,是以為虛線
3日志同步
3.1 小黃和小藍的回應MsgAppResp
2.4節小紅開始向小黃和小藍發送Message4.1和Message4.2,下面是小黃和小藍收到後的回複
- 小黃和小藍收到資訊後,各自也準備了一個空的Entry,并且向小紅回複了type為MsgAppResp的Mesaage(Message5.1和Message5.2)
此時,三位同學的日志狀态如下:
3.2 小紅确認日志記錄,繼續發送MsgApp
- 小紅收到小黃的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
此時日志狀态,小紅的日志由虛線變為實線
3.3 小黃和小藍确認日志記錄
- 小黃收到小紅Message6.1後,根據msg中的commit為1,修改自己的commit為1,然後發送type為MsgAppResp的Message7.1
- 同理,小藍也會修改自己的commit為1,然後傳回type為MsgAppResp的Message7.2
此時日志狀态,小藍和小黃由虛線變為實線
3.4 小紅的收尾
- 當小紅收到Message7.1後,檢查msg中的index和本地的prs[2].match_,兩者相等,不做任何操作
- 同理,小紅收到Message7.2後,檢查msg中的index和本地的prs[3].match_,兩者相等,不做任何操作