Raft 協議

       分佈式一致性協議 Raft,自 2013 年論文發表之後就受到了技術領域的熱捧,我認爲相對於其他分佈式一致性算法,Raft 有效的解決了分佈式一致性算法過於複雜及難於實現的問題,這也是 Raft 能異軍突起的主要因素。

 

Raft 協議有效的借鑑了美國總統大選的策略,採用精英(Raft 稱呼這個精英爲 Leader)領導全局的方案,整個集羣中只有 Leader 可以處理 client 發送過來的請求,其他非 Leader 節點即使接收到請求也必須將其轉發到 Leader 節點進行處理。Raft 集羣中的成員分三種角色:

  1. Leader
  2. Follower
  3. Condidate

Raft 的選舉過程

Raft 協議在集羣初始狀態下是沒有 Leader 的, 集羣中所有成員均是 Follower,在選舉開始期間所有 Follower 均可參與選舉,這時所有 Follower 的角色均轉變爲 Condidate, Leader 由集羣中所有的 Condidate 投票選出,最後獲得投票最多的 Condidate 獲勝,其角色轉變爲 Leader 並開始其任期,其餘落敗的 Condidate 角色轉變爲 Follower 開始服從 Leader 領導。這裏有一種意外的情況會選不出 Leader 就是所有 Condidate 均投票給自己,這樣無法決出票數多的一方,Raft 算法爲了解決這個問題引入了北洋時期袁世凱獲選大總統的謀略,即選不出 Leader 不罷休,直到選出爲止,一輪選不出 Leader,便令所有 Condidate 隨機 sleap(Raft 論文稱爲 timeout)一段時間,然後馬上開始新一輪的選舉,這裏的隨機 sleep 就起了很關鍵的因素,第一個從 sleap 狀態恢復過來的 Condidate 會向所有 Condidate 發出投票給我的申請,這時還沒有甦醒的 Condidate 就只能投票給已經甦醒的 Condidate ,因此可以有效解決 Condiadte 均投票給自己的故障,便可快速的決出 Leader。

選舉出 Leader 後 Leader 會定期向所有 Follower 發送 heartbeat 來維護其 Leader 地位,如果 Follower 一段時間後未收到 Leader 的心跳則認爲 Leader 已經掛掉,便轉變自身角色爲 Condidate,同時發起新一輪的選舉,產生新的 Leader。

Raft 的數據一致性策略

Raft 協議強依賴 Leader 節點來確保集羣數據一致性。即 client 發送過來的數據均先到達 Leader 節點,Leader 接收到數據後,先將數據標記爲 uncommitted 狀態,隨後 Leader 開始向所有 Follower 複製數據並等待響應,在獲得集羣中大於 N/2 個 Follower 的已成功接收數據完畢的響應後,Leader 將數據的狀態標記爲 committed,隨後向 client 發送數據已接收確認,在向 client 發送出已數據接收後,再向所有 Follower 節點發送通知表明該數據狀態爲committed。

Raft 如何處理 Leader 意外的?

  1. client 發送數據到達 Leader 之前 Leader 就掛了,因爲數據還沒有到達集羣內部,所以對集羣內部數據的一致性沒有影響,Leader 掛了之後,集羣會進行新的選舉產生新的 Leader,之前掛掉的 Leader 重啓後作爲 Follower 加入集羣,並同步 Leader 上的數據。這裏最好要求 client 有重試機制在一定時間沒有收到 Leader 的數據已接收確認後進行一定次數的重試,並再次向新的 Leader 發送數據來確保業務的流暢性。

  2. client 發送數據到 Leader,數據到達 Leader 後,Leader 還沒有開始向 Folloers 複製數據,Leader就掛了,此時數據仍被標記爲 uncommited 狀態,這時集羣會進行新的選舉產生新的 Leader,之前掛掉的 Leader 重啓後作爲 Follower 加入集羣,並同步 Leader 上的數據,來保證數據一致性,之前接收到 client 的數據由於是 uncommited 狀態所以可能會被丟棄。這裏同樣最好要求 client 有重試機制通過在一定時間在沒有收到 Leader 的數據已接收確認後進行一定次數的重試,再次向新的 Leader 發送數據來確保業務的流暢性。

  3. client 發送數據到 Leader, Leader 接收數據完畢後標記爲 uncommited,開始向 Follower複製數據,在複製完畢一小部分 Follower 後 Leader 掛了,此時數據在所有已接收到數據的 Follower 上仍被標記爲 uncommitted,但國不可一日無君,此時集羣將進行新的選舉,而擁有最新數據的 Follower 變換角色爲 Condidate,也就意味着 Leader 將在擁有最新數據的 Follower 中產生,新的 Leader 產生後所有節點開始從新 Leader 上同步數據確保數據的一致性,包括之前掛掉後恢復了狀態的 老Leader,這時也以 Follower 的身份同步新 Leader 上的數據。

  4. client 發送數據到 Leader,Leader 接收數據完畢後標記爲 uncommitted,開始向 Follower 複製數據,在複製完畢所有 Follower 節點或者大部分節點(大於 N/2),並接收到大部分節點接收完畢的響應後,Leader 節點將數據標記爲 committed,這時 Leader 掛了,此時已接收到數據的所有 Follower 節點上的數據狀態由於還沒有接收到 Leader 的 commited 通知,均處於 uncommited 狀態。這時集羣進行了新的選舉,新的 Leader 將在擁有最新數據的節點中產生,新的 Leader 產生後,由於 client 端因老 Leader 掛掉前沒有通知其數據已接收,所以會向新的 Leader 發送重試請求,而新的 Leader 上已經存在了這個之前從老 Leader 上同步過來的數據,因此 Raft 集羣要求各節點自身實現去重的機制,保證數據的一致性。

  5. 集羣腦裂的一致性處理,多發於雙機房的跨機房模式的集羣。假設一個 5 節點的 Raft 集羣,其中三個節點在 A 機房,Leader 節點也在 A 機房,兩個節點在 B 機房。突然 A、B 兩個機房之間因其他故障無法通訊,那麼此時 B 機房中的 2 個Follower 因爲失去與 Leader 的聯繫,均轉變自身角色爲 Condidate。根據 Leader 選舉機制,B 機房中產生了一個新的 Leader,這就發生了腦裂即存在 A 機房中的老 Leader 的集羣與B機房新 Leader 的集羣。Raft 針對這種情況的處理方式是老的 Leader 集羣雖然剩下三個節點,但是 Leader 對數據的處理過程還是在按原來 5 個節點進行處理,所以老的 Leader 接收到的數據,在向其他 4 個節點複製數據,由於無法獲取超過 N/2 個 Follower 節點的複製完畢數據響應(因爲無法連接到 B 機房中的 2個節點),所以 client 在向老 Leader 發送的數據請求均無法成功寫入,而 client 向B機房新 Leader 發送的數據,因爲是新成立的集羣,所以可以成功寫入數據,在A、B兩個機房恢復網絡通訊後,A 機房中的所有節點包括老 Leader 再以 Follower 角色接入這個集羣,並同步新 Leader 中的數據,完成數據一致性處理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章