日志複制可以說是Raft叢集的核心之一,保證了Raft資料的一緻性,下面通過幾張圖檔介紹Raft叢集中日志複制的邏輯與流程;

在一個Raft叢集中隻有Leader節點能夠接受用戶端的請求,由Leader向其他Follower轉發所有請求日志,并且有那麼兩條規則:Leader不删除任何日志、Follower隻接收Leader所發送的日志資訊;
此圖介紹了Raft叢集中日志的組成結構,日志由序号與條目組成,每個條目又由任期與指令組成,committed範圍内為已送出的日志是指過半節點已經接收并存儲的日志;
上圖從整個上介紹了Raft叢集的日志複制流程,Leader接收到指令後寫入到本地日志,在随後的心跳中(AppendEntries)往其他追随者發送該條目,等待收到過半追随者響應後将該條目标志位已送出狀态,并發往狀态機執行,完成後傳回結果給用戶端;在後續心跳包(AppendEntries)中通知所有追随者哪些條目為已送出狀态,以便追随者更新在自己狀态機中執行該指令; 隻有Leader能夠接受用戶端的指令,追随者隻能夠接收上司者的AppendEntries請求;
在Raft叢集中可通過條目索引号、任期号唯一确定一個條目,該條目前序所有條目也是一緻的,如上圖中索引号為5的條目為已送出狀态的條目,則從索引号1到5的所有條目均為已送出的狀态;
上圖中Leader發送AppendEntries請求時帶有其前序索引位置4、前序任期号2,發往Follower1、Follower2;
Follower1由于前序索引與前序任期能比對本地條目是以将會接受該請求;
Follower2由于前序索引與前序任期未能夠比對是以拒絕該請求;
Raft處理日志不一緻的情況是通過強制追随者複制上司者日志來調整日志一緻性的,是以當追随者與上司者出現日志不一緻時,追随者日志将會被上司者日志覆寫;
要使上司者與追随者保持一緻性的狀态,需要兩者找到一緻性的位置,删除追随者該位置之後所有日志條目,發送上司者日志給追随者;
上司者通過在每一個追随者維護了一個 nextIndex,表示下一個需要發送給跟随者的日志條目索引位址,上司者剛獲得選舉時,初始化所有 nextIndex 值為自己的最後一條日志的index加1;當追随者的日志和上司者不一緻,那在下一次的AppendEntries時的一緻性檢查會失敗,被追随者拒絕後,上司者就會減小 nextIndex 值進行重試,nextIndex 會在某位置使上司者和追随者日志達成一緻。
當日志達成一緻時,追随者會接受該AppendEntries請求,這時追随者沖突的日志條目将全部被上司者的日志所覆寫。一旦AppendEntries成功,那麼跟随者的日志就會和上司人保持一緻,并且在接下來的任期裡一直繼續保持。
參考資料:
http://ramcloud.stanford.edu/raft.pdf
文章首發位址:Solinx
http://www.solinx.co/archives/1221