raft協議詳解
1、raft協議是什麼?
分散式系統之於單機系統,優勢之一就是有更好的容錯性。
- 比如,一臺機器上的磁碟損壞,資料丟失,可以從另一臺機器上的磁碟恢復(分散式系統會對資料做備份)
- 比如,叢集中某些機器當機,整個叢集還可以對外提供服務
這是如何做到的?比較容易的一個想法就是備份(backup)。一個系統的工作模是:接受客戶端的command,系統進行處理,將處理的結果返回給客戶端。由此可見,系統裡的資料可能會因為command而變化。
實現備份的做法之一就是複製狀態機(Repilcated State Machine,RSM),它有一個很重要的性質——確定性(deterministic):
- 如果兩個相同的、確定性的狀態從同一狀態開始,並且以相同的順序獲得相同的輸入,那麼這兩個狀態機將會生成相同的輸出,並且結束在相同的狀態
也就是說,如果我們能按順序將command作用於狀態機,它就可以產生相同的狀態和相同的輸出
那麼一個狀態機如何實現呢?如下圖所示(來自raft協議):
上圖中,每個RSM都有一個replicated log,儲存的是來自客戶端的commands。每個RSM中replicate log中commads的順序都是相同的,狀態機按順序處理replicate log中的command,並將處理的結果返回給客戶端。由於狀態機具有確定性,因此每個狀態機的輸出和狀態都是相同的。
上圖中有一個模組——Consensus Module剛剛沒有提及。這個模組用於保證每個server上Log的一致性!
- 如果不做任何保障,直接將commad暴力寫入,一旦伺服器當機或者出現什麼其他故障,就會導致這個Log丟失,並且無法恢復。而出現故障的可能性是很高的,這就導致系統不可用
- raft就是Consensus Module的一個實現
因此,raft是一致性協議,是用來保障servers上副本一致性的一種演算法。
2、raft協議原理
下面將看論文時我認為的重要點進行記錄。
raft協議遵循的性質
-
Election Safty
- 每一個任期內只能有一個領導人
-
Leader Append-Only
- leader只能追加日誌條目,不能重寫或者刪除日誌條目
-
Log Maching
- 如果兩個日誌條目的index和term都相同,則兩個如果日誌中,兩個條目及它們之前的日誌條目也完全相同
-
Leader Completeness
- 如果一條日誌被commited過,那麼大於該日誌條目任期的日誌都應該包含這個點
-
State Machine Safety
- 如果一個server將某個特定index的日誌條目交由狀態機處理了,那麼對於其他server,交由狀態及處理的log中相同index的日誌條目應該相同
2.1 如何保證Election Safty
raft中,只要candidate獲得多數投票,就可以成為領導人。follower在投票的時候遵循兩個條件:
- 先到先得
- cadidate的term大於follower的term,或者兩個term相等,但cadidate的index大於follower的index
對於選舉結果:
- 如果票被瓜分,產生兩個leader,這次選舉失效,進行下一輪的選舉
- 只有一個leader的情況是被允許的
這裡重要的一點是:如何保證在有限的時間內確定出一個候選人,而不會總是出現票被瓜分的情況?raft使用了一個比較優雅的實現方式,隨機選舉超時(randomize election timeouts)。這就使得每個server的timeout不一樣,發起新一輪選舉的時候,有些server還不是voter;或者一些符合條件的candidate還沒有參加下一輪。這種做法使得單個leader會很快被選舉出來。
2.2 如何保證Log Matching
Leader在進行AppendEntry RPCs的時候,這個訊息中會攜帶preLogIndex和preLogTerm這兩個資訊,follower收到訊息的時候,首先判斷它最新日誌條目的index和term是否和rpc中的一樣,如果一樣,才會append.
這就保證了新加日誌和其前一條日誌一定是一樣的。從第一條日誌起就開始遵循這個原理,很自然地可以作出這樣的推斷。
2.3 如何保證Leader Completeness
這個在raft協議中是有完整證明的,這個證明比較簡短,用反正法,我在看的時候加了一些標註。
假設leaderU是第一個沒有包含leaderT中commitT點(T
基於這個假設,一個事實是,開始選舉的時候,U中就不包含T中的commit點由於leaderT有commitT點,說明在任期T內,有大部分的follower都有commitT的點。這就說明,一定存在一個voter,它包含了commitT點,並且它投票給了leaderU如果leaderU和這個voter有相同的term,那麼leaderU的日誌長度一定大於等於這個voter(否則會因為index小而被拒絕投票),那麼leaderU肯定包含了voter的所有資訊(這個是由Log Matching的屬性決定的,它們包含有相同的term,因此相同index的日誌條目肯定相同),leaderU中肯定包含commit點,這與假設矛盾如果leaderU和這個voter的term不同,那麼leaderU的日誌index一定大於等於voter的index。也就是說,為leaderU新增最後一條entry的那個leader因該已經包含提交的日誌(這是因為leaderU的leader的term>leaderU的term>voter的term,而leaderU是的一個不符合條件的任期,所以leaderU的leader應該是符合條件的,肯定就包含了voter的commit點),即包含commit點,根據Log Maching的原則,leaderU裡面一定包含了這一點,這與假設矛盾因此,leader completeness是可以保證的
2.4 raft協議中有一個約定,不能提交之前任期內log entry作為commit點。這是為什麼?
這個問題主要是raft協議中commiting entries from previous term部分看的時候有點困惑,開始誤解成了這個約定是用來保證之前任期內已經被複制到大多數server卻沒有被提交的日誌在新的仍期內不會被覆蓋。
實際上,論文中的figrure8的過程是一個正確的過程。
在(c)中,index=2並沒有被提交,在(d)中被複制了是一個正確的做法。論文想闡述的是:如果在(c)中,leader提交了這個之前任期內的entry,在(d)中依然會被覆蓋,也就是說被commit的entry覆蓋了,這是一個錯誤!因此約定“can not commit entries from previous term”
2.5 cluster membership changes
如果叢集的配置發生了變化,例如,新加入幾臺server,掛掉幾臺server。這是會影響選舉的。
例如,如果新增了伺服器,卻沒有更新原來server的配置,會導致leader election只有老機器在參與又比如,如果直接將新的配置更新到leader這個方法是有問題的。如果leader沒有及時通知到所有的伺服器,那麼存在部分server是老配置,部分server是新配置,從而可能會產生兩個leader,如下圖的情況:
raft的解決方法就是two phase approch,引入一個過度配置,稱為共同一致狀態。具體的做法和圖示:
leader收到更新配置請求的時候,產生一個(old,new)entry,並append進日誌通過rpc讓follower追加這條日誌如果順利,將這條日誌commit產生new entry, append到日誌通過rpc讓follower追加如果順利commit,從而完成新配置的生成
考慮上述過程:
1,2兩個階段,如果過程中出現問題,大多數情況old成為新的leader
因為此時,擁有(old,new)entry的server並不是大多數如果說,已經複製給大多數server,只是未提交,那麼(old,new)是有可能被選為leader,不過這沒有什麼太大的影響,因為新的leader在被選之後,會傳送一條no-op的rpc,這個時候(old,new)就會被提交。重要的是,此時也僅有可能一個leader被選出,old不肯那個被選舉為leader.3,4,5階段,大多數情況(old,new)成為leader,例外與上條類似5階段就是new成為leader
2.6 log過長或日誌回放時間過長怎麼辦?
此時就需要做log compaction
raft採用的方法是寫時複製的snapshot(寫是複製在linux中可以通過fork來完成)
寫時複製主要是處於效能考慮的,如果state machine資料太多,snapshot將會耗費大量的時間,也許會導致系統可用性大大降低
相關文章
- Raft協議精解Raft協議
- raft協議Raft協議
- Raft協議和ZAB協議Raft協議
- 分散式一致性協議Raft全面詳解(建議收藏)分散式協議Raft
- 實現 Raft 協議Raft協議
- raft協議初識Raft協議
- Raft協議學習筆記Raft協議筆記
- Raft 協議學習筆記Raft協議筆記
- FTP協議詳解FTP協議
- TCP協議詳解TCP協議
- Kraft協議詳解Raft協議
- VxLAN協議詳解協議
- HTTPS協議詳解HTTP協議
- Gossip 協議詳解Go協議
- USB協議詳解協議
- SPI協議詳解協議
- HTTP協議詳解HTTP協議
- QUIC協議詳解UI協議
- WebSocket 協議詳解Web協議
- UDP協議詳解UDP協議
- http協議/cookie詳解/session詳解HTTP協議CookieSession
- 網路通訊協議-ICMP協議詳解!協議
- 網路通訊協議-TCP協議詳解!協議TCP
- 網路通訊協議-HTTP協議詳解!協議HTTP
- 網路通訊協議-SMTP協議詳解!協議
- 組播協議詳解協議
- HTTP 3協議詳解HTTP協議
- tcp/ip協議和opc協議對比詳解TCP協議
- etcd套路(二)etcd核心之raft協議Raft協議
- TCP傳輸協議詳解TCP協議
- IMAP協議之BODYSTRUCTURE詳解協議Struct
- V-By-One協議詳解協議
- python 多型 協議詳解Python多型協議
- OSPF 路由協議詳解(一)路由協議
- MQTT 協議 Keep Alive 詳解MQQT協議
- 網路協議之:socket協議詳解之Datagram Socket協議
- 常見協議埠號對應 + 重要協議詳解協議
- consul 原始碼解析(一)raft 協議實現原始碼Raft協議