Raft 分佈式系統 一致性協議

Raft

Raft is a consensus algorithm that is designed to be easy to understand. It’s equivalent to Paxos in fault-tolerance and performance. The difference is that it’s decomposed into relatively independent subproblems, and it cleanly addresses all major pieces needed for practical systems. We hope Raft will make consensus available to a wider audience, and that this wider audience will be able to develop a variety of higher quality consensus-based systems than are available today.

Raft類似Paxos,是一個分佈式的一致性的協議,而且更容易理解。

Raft一致性算法

Raft協議主要使用了兩種策略。一是將複雜問題進行分解,在Raft協議中,一致性問題被分解爲:leader election、log replication、safety三個簡單問題;二是減少狀態空間中的狀態數目。下面我們詳細看一下Raft協議是怎樣設計的。

在Raft體系中,有一個強leader,由它全權負責接收客戶端的請求命令,並將命令作爲日誌條目賦值給其他服務器,在確認安全的時候,將日誌命令提交執行。當leader故障時,會選舉產生一個新的leader。在強leader的幫助下,Raft將一致性問題分解爲了三個子問題:

  • leader選舉:當已有的leader故障時必須選出一個新的leader
  • 日誌複製:leader接受來自客戶端的命令,記錄爲日誌,並複製給集羣中的其他服務器,並強制其他節點的日誌與leader保持一致。
  • 安全safety措施:通過一些措施確保系統的安全性,如確保所有狀態機按照相同順序執行相同命令的措施。
基本概念

一個Raft集羣擁有多個服務器,典型值是5,這樣可以容忍兩臺服務器出現故障。服務器可能會處於如下三種角色:leader、candidate、follower,正常運行的情況下,會有一個leader,其他全爲follower,follower只會響應leader和candidate的請求,而客戶端的請求則全部由leader處理,即使有客戶端請求了一個follower也會將請求重定向到leader。candidate代表候選人,出現在選舉leader階段,選舉成功後candidate將會成爲新的leader。

從狀態轉換關係圖中可以看出,集羣剛啓動時,所有節點都是follower,之後在time out信號的驅使下,follower會轉變成candidate去拉取選票,獲得大多數選票後就會成爲leader,這時候如果其他候選人發現了新的leader已經誕生,就會自動轉變爲follower;而如果另一個time out信號發出時,還沒有選舉出leader,將會重新開始一次新的選舉。可見,time out信號是促使角色轉換得關鍵因素,類似於操作系統中得中斷信號。

在Raft協議中,將時間分成了一些任意長度的時間片,稱爲term,term使用連續遞增的編號的進行識別。每一個term都從新的選舉開始,candidate們會努力爭取稱爲leader。一旦獲勝,它就會在剩餘的term時間內保持leader狀態,在某些情況下(如term3)選票可能被多個candidate瓜分,形不成多數派,因此term可能直至結束都沒有leader,下一個term很快就會到來重新發起選舉。

term也起到了系統中邏輯時鐘的作用,每一個server都存儲了當前term編號,在server之間進行交流的時候就會帶有該編號,如果一個server的編號小於另一個的,那麼它會將自己的編號更新爲較大的那一個;如果leader或者candidate發現自己的編號不是最新的了,就會自動轉變爲follower;如果接收到的請求的term編號小於自己的當前term將會拒絕執行。

server之間的交流是通過RPC進行的。只需要實現兩種RPC就能構建一個基本的Raft集羣:

  • RequestVote RPC:它由選舉過程中的candidate發起,用於拉取選票。
  • AppendEntries RPC:它由leader發起,用於複製日誌或者發送心跳信號。

Raft通過心跳機制發起leader選舉。節點都是從follower狀態開始的,如果收到了來自leader或candidate的RPC,那它就保持follower狀態,避免爭搶成爲candidate。Leader會發送空的AppendEntries RPC作爲心跳信號來確立自己的地位,如果follower一段時間(election timeout)沒有收到心跳,它就會認爲leader已經掛了,發起新的一輪選舉。

選舉發起後,一個follower會增加自己的當前term編號並轉變爲candidate。它會首先投自己一票,然後向其他所有節點並行發起RequestVote RPC,之後candidate狀態將可能發生如下三種變化:

  • 贏得選舉,稱爲leader: 如果它在一個term內收到了大多數的選票,將會在接下的剩餘term時間內稱爲leader,然後就可以通過發送心跳確立自己的地位。(每一個server在一個term內只能投一張選票,並且按照先到先得的原則投出)
  • 其他server稱爲leader:在等待投票時,可能會收到其他server發出AppendEntries RPC心跳信號,說明其他leader已經產生了。這時通過比較自己的term編號和RPC過來的term編號,如果比對方大,說明leader的term過期了,就會拒絕該RPC,並繼續保持候選人身份; 如果對方編號不比自己小,則承認對方的地位,轉爲follower
  • 選票被瓜分,選舉失敗: 如果沒有candidate獲取大多數選票, 則沒有leader產生, candidate們等待超時後發起另一輪選舉. 爲了防止下一次選票還被瓜分,必須採取一些額外的措施, raft採用隨機election timeout的機制防止選票被持續瓜分.通過將timeout隨機設爲一段區間上的某個值, 因此很大概率會有某個candidate率先超時然後贏得大部分選票
日誌複製過程

一旦leader被選舉成功,就可以對客戶端提供服務了。客戶端提交每一條命令都會被按順序記錄到leader的日誌中,每一條命令都包含term編號和順序索引,然後向其他節點並行發送AppendEntries RPC用以複製命令(如果命令丟失會不斷重發),當複製成功也就是大多數節點成功複製後,leader就會提交命令,即執行該命令並且將執行結果返回客戶端,raft保證已經提交的命令最終也會被其他節點成功執行。leader會保存有當前已經提交的最高日誌編號。順序性確保了相同日誌索引處的命令是相同的,而且之前的命令也是相同的。當發送AppendEntries RPC時,會包含leader上一條剛處理過的命令,接收節點如果發現上一條命令不匹配,就會拒絕執行。

在Raft中,leader通過強制follower複製自己的日誌來解決上述日誌不一致的情形,那麼衝突的日誌將會被重寫。爲了讓日誌一致,先找到最新的一致的那條日誌(如f中索引爲3的日誌條目),然後把follower之後的日誌全部刪除,leader再把自己在那之後的日誌一股腦推送給follower,這樣就實現了一致。而尋找該條日誌,可以通過AppendEntries RPC,該RPC中包含着下一次要執行的命令索引,如果能和follower的當前索引對上,那就執行,否則拒絕,然後leader將會逐次遞減索引,直到找到相同的那條日誌。

宏觀結構

首先我們假設有三個 RaftNode,每個 RaftNode 都會開設一個端口,這個端口的作用就是接受客戶端的(Get/Set)請求以及其它 RaftNode 的 RPC 請求。這裏需要說明的是多數著名開源項目一般會選擇兩個端口,一個面向客戶端,一個面向 RPC,好處是可以選擇不同的 IP 地址,客戶端端口可以面向外網,而 RPC 則是安全的內網通信。作者選擇了一個端口是因爲只用於內網,在實現上也會簡單不少。

當選 Leader 的條件

並不是任意一個節點都可以變成 Leader。如果要當 Leader,這個節點包含的日誌必須最全。Candidate 通過 RequestVote 消息拉票的時候,需要攜帶當前日誌列表的 lastLogIndex 和相應日誌的 term 值(尾部日誌的 term 和 index )。 其它節點需要和這兩個值進行匹配,凡是沒自己新的拉票請求都拒絕。

日誌壓縮

隨着日誌大小的增長,會佔用更多的內存空間,處理起來也會耗費更多的時間,對系統的可用性造成影響,因此必須想辦法壓縮日誌大小。Snapshotting是最簡單的壓縮方法,系統的全部狀態會寫入一個snapshot保存起來,然後丟棄截止到snapshot時間點之前的所有日誌。

文獻

https://raft.github.io

https://raft.github.io/raft.pdf

http://verdi.uwplse.org

https://www.cl.cam.ac.uk/~ms705/pub/papers/2015-osr-raft.pdf

有時候看博客總是覺得沒說清楚呢??但是看源碼感覺還是無能爲力啊。。。下次繼續看看

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