角色:
- Leader:接收客戶端的請求,處理日誌
- Candidate:用於選舉Leader的中間角色
- Follower:響應來自Leader或者Candidate的請求
選舉過程:
- 集羣初始都是Follower,無Leader。
- Raft中各節點會有一個隨機timeout時間,第一個結束timeout的Follower轉換爲Candidate,並遞增任期開始選舉,投票給自己併發送給其他Follower投票請求。
- 還未結束timeout的Follower只能響應Candidate的投票請求。
- 當收到大多數Follower的選票時,Candidate轉換爲Leader,其他Candidate則轉換爲Follower。
- Leader週期性發送心跳保持自己Leader角色。
注意:
- 所有節點初始狀態都是Follower角色
- timeout時間內沒有收到Leader的請求,則轉換爲Candidate進行選舉
- Candidate在選舉時,一個節點在一個任期內只能給一個Candidate投票,任期相同則選票先到先得;收到其他節點的請求,如果請求中的任期大於等於當前Candidate的任期,則認爲其他節點爲Leader,自身轉換爲Follower;若小與自身的任期,則拒絕請求並保持Candidate角色;發現Leader則轉換爲Follower
- Leader在收到更高任期的請求後轉換爲Follower
- 一段時間後仍舊沒有Leader,可能平票,則在選舉超時後重新發起一輪選舉
數據一致性:
- Client發送請求到Leader
- Leader記錄日誌,標記爲uncommitted,並複製給Follower
- Follower會在接收後,記錄日誌,標記爲uncommitted
- 成功複製一小部分Follower
- 成功複製大於N>2的Follower,Leader將日誌標記爲committed,向Client發送已確認接收
- 再向所有Follower節點發送通知,表明該日誌狀態爲committed,Follower接收後變更標記
一致性意外處理:
上述數據一致性,每個環節都可能出現Leader掛掉的情況
- Client -> Leader,Client發到Leader之前,Leader掛了。則重新選舉新Leader,Client重試
- Client -> Leader-> Follower,Leader發到Follower之前,Leader掛了。則重新選舉新Leader,Client重試
- Client -> Leader-> Follower,複製了一小部分Follower,Leader掛了,Leader日誌標記爲uncommitted。則從已標記uncommitted的Follower中,選舉Leader,再繼續進行復制。
- Client -> Leader-> Follower,複製了大於N/2的Follower,Leader掛了。Leader日誌標記爲committed,但Client還未接收到已確認接收的響應。則從已標記uncommitted的Follower中,選舉Leader。Client發送重試請求,Raft集羣各節點進行數據去重。
- 有A,B兩個機房,三個節點在A,兩個節點在B,Leader在A。當A,B網絡中斷,B中兩個節點會選舉新Leader。老Leader集羣剩下三個節點,但還是按五個節點來處理,所以無法完成大於N/2個節點的複製響應。Client向老Leader發送的請求無法寫入,向新header發送的數據可以寫入。當A,B網絡正常,A機房三個節點以Follower角色接入集羣。
Raft 協議圖示
1.選舉開始前,各節點都是Follower,各節點開始隨機timeout
2.第一個結束timeout的Follower,遞增任期並轉換爲Candidate,投票自身並向其他Follower發送投票請求
3.當Candidate接收到大多數Follower的投票,則轉換成Leader,其他節點轉換爲Follower。Leader會週期性發送心跳確認Leader
4.右鍵Leader,可發送request請求。Leader將日誌標記爲uncommited,並複製到Follower
5.Follower接收到請求,並標記日誌爲uncommited,響應Leader
6.Leader收到大於N/2個Follower的響應,將日誌標記爲commited,並響應客戶端數據已確認
7.Leader向所有Follower節點發送通知,標記日誌爲commited
8.停掉Leader。其他節點在timeout時間內接收不到Leader的心跳,開始新的選舉
9.繼續請求,並記錄日誌
10.重啓S5節點,以Follower角色加入集羣,並同步之前的日誌