摘要:每個在收到的心跳信息后會重啟定時器,從而避免在正常工作時,會發生選舉的情況。日志復制當選出后,它會開始接受客戶端請求,每個請求會帶有一個指令,可以被回放到狀態機中。
一致性算法 - Raft Raft 狀態
一個 Raft 集群包含若干個服務器節點;通常是 5 個,這允許整個系統容忍 2 個節點的失效,每個節點處于以下三種狀態之一:
follower(跟隨者) :所有結點都以 follower 的狀態開始。如果沒收到 leader消息則會變成 candidate狀態。
candidate(候選人):會向其他結點“拉選票”,如果得到大部分的票則成為leader。這個過程就叫做Leader選舉(Leader Election)。
leader(領導者):所有對系統的修改都會先經過leader。
Raft 一致性算法Raft通過選出一個leader來簡化日志副本的管理,例如,日志項(log entry)只允許從leader流向follower。
基于leader的方法,Raft算法可以分解成三個子問題:
Leader election (領導選舉):原來的leader掛掉后,必須選出一個新的leader
Log replication (日志復制):leader從客戶端接收日志,并復制到整個集群中
Safety (安全性):如果有任意的server將日志項回放到狀態機中了,那么其他的server只會回放相同的日志項
Leader election (領導選舉)Raft 使用一種心跳機制來觸發領導人選舉。當服務器程序啟動時,他們都是 follower(跟隨者) 身份。如果一個跟隨者在一段時間里沒有接收到任何消息,也就是選舉超時,然后他就會認為系統中沒有可用的領導者然后開始進行選舉以選出新的領導者。要開始一次選舉過程,follower 會給當前term加1并且轉換成candidate狀態。
然后他會并行的向集群中的其他服務器節點發送請求投票的 RPCs 來給自己投票。候選人的狀態維持直到發生以下任何一個條件發生的時候,
他自己贏得了這次的選舉
如果這個節點贏得了半數以上的vote就會成為leader,每個節點會按照first-come-first-served的原則進行投票,并且一個term中只能投給一個節點, 這樣就保證了一個term最多有一個節點贏得半數以上的vote。
當一個節點贏得選舉, 他會成為leader, 并且給所有節點發送這個信息, 這樣所有節點都會回退成follower。
其他的服務器成為領導者
如果在等待選舉期間,candidate接收到其他server要成為leader的RPC,分兩種情況處理:
如果leader的term大于或等于自身的term,那么改candidate 會轉成follower 狀態
如果leader的term小于自身的term,那么會拒絕該 leader,并繼續保持candidate 狀態
一段時間之后沒有任何一個獲勝的人
有可能,很多follower同時變成candidate,導致沒有candidate能獲得大多數的選舉,從而導致無法選出主。當這個情況發生時,每個candidate會超時,然后重新發增加term,發起新一輪選舉RPC。需要注意的是,如果沒有特別處理,可能出導致無限地重復選主的情況。
Raft采用隨機定時器的方法來避免上述情況,每個candidate選擇一個時間間隔內的隨機值,例如150-300ms,采用這種機制,一般只有一個server會進入candidate狀態,然后獲得大多數server的選舉,最后成為主。每個candidate在收到leader的心跳信息后會重啟定時器,從而避免在leader正常工作時,會發生選舉的情況。
Log replication (日志復制)當選出 leader 后,它會開始接受客戶端請求,每個請求會帶有一個指令,可以被回放到狀態機中。leader 把指令追加成一個log entry,然后通過AppendEntries RPC并行的發送給其他的server,當改entry被多數派server復制后,leader 會把該entry回放到狀態機中,然后把結果返回給客戶端。
當 follower 宕機或者運行較慢時,leader 會無限地重發AppendEntries給這些follower,直到所有的follower都復制了該log entry。
raft的log replication保證以下性質(Log Matching Property):
如果兩個log entry有相同的index和term,那么它們存儲相同的指令
如果兩個log entry在兩份不同的日志中,并且有相同的index和term,那么它們之前的log entry是完全相同的
其中特性一通過以下保證:
leader在一個特定的term和index下,只會創建一個log entry
log entry不會改變它們在日志中的位置
特性二通過以下保證:
AppendEntries會做log entry的一致性檢查,當發送一個AppendEntriesRPC時,leader會帶上需要復制的log entry前一個log entry的(index, iterm)
如果follower沒有發現與它一樣的log entry,那么它會拒絕接受新的log entry 這樣就能保證特性二得以滿足。
安全性 選舉限制在一些一致性算法中,即使一臺server沒有包含所有之前已提交的log entry,也能被選為主,這些算法需要把leader上缺失的日志從其他的server拷貝到leader上,這種方法會導致額外的復雜度。相對而言,raft使用一種更簡單的方法,即它保證所有已提交的log entry都會在當前選舉的leader上,因此,在raft算法中,日志只會從leader流向follower。
為了實現上述目標,raft在選舉中會保證,一個candidate只有得到大多數的server的選票之后,才能被選為主。得到大多數的選票表明,選舉它的server中至少有一個server是擁有所有已經提交的log entry的,而leader的日志至少和follower的一樣新,這樣就保證了leader肯定有所有已提交的log entry。
提交之前任期內的日志條目領導人知道一條當前任期內的日志記錄是可以被提交的,只要它被存儲到了大多數的服務器上。如果一個領導人在提交日志條目之前崩潰了,未來后續的領導人會繼續嘗試復制這條日志記錄。然而,一個領導人不能斷定一個之前任期里的日志條目被保存到大多數服務器上的時候就一定已經提交了。下圖展示了一種情況,一條已經被存儲到大多數節點上的老日志條目,也依然有可能會被未來的領導人覆蓋掉。
如上圖的例子,圖(c)就發生了一個log entry雖然已經復制到大多數的服務器,但是仍然有可能被覆蓋掉的可能,如圖(d),整個發生的時序如下:
圖a中,S1被選為主,然后復制到log index為2的log entry到S2上
圖b中,S1掛掉,然后S5獲得了S3,S4和自身的選舉,成為leader,然后,其從客戶端收到了一個新的log entry(3)
圖c中,S5掛掉,S1重新正常工作,又被選為主,繼續復制log entry(2),在log entry(2)被提交前,S1又掛掉
圖d中,S5又重新被選為領導者,然后,會把term 3的log entry覆蓋到其他log index為2的log entry
為了上圖描述的情況,Raft 永遠不會通過計算副本數目的方式去提交一個之前任期內的日志條目。只有領導人當前任期里的日志條目通過計算副本數目可以被提交;一旦當前任期的日志條目以這種方式被提交,那么由于日志匹配特性,之前的日志條目也都會被間接的提交。例如,圖e中,如果S1在掛掉前把log entry(4)復制到了大多數的server后,就能保證之前的log entry(2)被提交了,之后S5也就不可能被選為領導者了。
安全性論證以反證法來證明,假設任期 T 的領導人(領導人 T)在任期內提交了一條日志條目,但是這條日志條目沒有被存儲到未來某個任期的領導人的日志中。設大于 T 的最小任期 U 的領導人 U 沒有這條日志條目。
如果 S1 (任期 T 的領導者)提交了一條新的日志在它的任期里,然后 S5 在之后的任期 U 里被選舉為領導人,然后至少會有一個機器,如 S3,既擁有來自 S1 的日志,也給 S5 投票了。
在領導人 U 選舉的時候一定沒有那條被提交的日志條目(領導人從不會刪除或者覆蓋任何條目)。
領導人 T 復制這條日志條目給集群中的大多數節點,同時,領導人U 從集群中的大多數節點贏得了選票。因此,至少有一個節點(投票者、選民)同時接受了來自領導人T 的日志條目,并且給領導人U 投票了,這個投票者是產生這個矛盾的關鍵。
這個投票者必須在給領導人 U 投票之前先接受了從領導人 T 發來的已經被提交的日志條目;否則他就會拒絕來自領導人 T 的附加日志請求(因為此時他的任期號會比 T 大)。
投票者在給領導人 U 投票時依然保有這條日志條目,因為任何中間的領導人都包含該日志條目(根據上述的假設),領導人從不會刪除條目,并且跟隨者只有和領導人沖突的時候才會刪除條目。
投票者把自己選票投給領導人 U 時,領導人 U 的日志必須和投票者自己一樣新。這就導致了兩者矛盾之一。
首先,如果投票者和領導人 U 的最后一條日志的任期號相同,那么領導人 U 的日志至少和投票者一樣長,所以領導人 U 的日志一定包含所有投票者的日志。這是另一處矛盾,因為投票者包含了那條已經被提交的日志條目,但是在上述的假設里,領導人 U 是不包含的。
除此之外,領導人 U 的最后一條日志的任期號就必須比投票人大了。此外,他也比 T 大,因為投票人的最后一條日志的任期號至少和 T 一樣大(他包含了來自任期 T 的已提交的日志)。創建了領導人 U 最后一條日志的之前領導人一定已經包含了那條被提交的日志(根據上述假設,領導人 U 是第一個不包含該日志條目的領導人)。所以,根據日志匹配特性,領導人 U 一定也包含那條被提交當然日志,這里產生矛盾。
因此,假設不成立,所有比 T 大的領導人一定包含了所有來自 T 的已經被提交的日志。日志匹配原則保證了未來的領導人也同時會包含被間接提交的條目
跟隨者和候選人崩潰跟隨者或者候選人崩潰,會按如下處理:
領導者會不斷給它發送選舉和追加日志的RPC,直到成功
跟隨者會忽略它已經處理過的追加日志的RPC
時間和可用性領導人選舉是 Raft 中對時間要求最為關鍵的方面。Raft 可以選舉并維持一個穩定的領導人,只要系統滿足下面的時間要求:
廣播時間(broadcastTime) << 選舉超時時間(electionTimeout) << 平均故障間隔時間(MTBF)
廣播時間指的是從一個服務器并行的發送 RPCs 給集群中的其他服務器并接收響應的平均時間;
選舉超時時間就是選舉的超時時間限制
平均故障間隔時間就是對于一臺服務器而言,兩次故障之間的平均時間。
選舉超時時間要大于廣播時間的原因是,防止跟隨者因為還沒收到領導者的心跳,而重新選主。
選舉超時時間要小于MTBF的原因是,防止選舉時,能正常工作的server沒有達到大多數。
對于廣播時間,一般在[0.5ms,20ms]之間,而平均故障間隔時間一般非常大,至少是按照月為單位。因此,一般選舉超時時間一般選擇范圍為[10ms,500ms]。因此,當領導者掛掉后,能在較短時間內重新選主。
動畫演示 Rafthttp://thesecretlivesofdata.c...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/24191.html
摘要:作者屈鵬本文為源碼解析系列的第二篇,按照計劃首先將為大家介紹依賴的周邊庫。值得注意的是,這個中并不包括持久化,也不會將應用到應用程序自己的狀態機的接口。在下一次這個節點調用時,便可以取出這部分被確認的消息,并應用到狀態機中了。 作者:屈鵬 本文為 TiKV 源碼解析系列的第二篇,按照計劃首先將為大家介紹 TiKV 依賴的周邊庫 raft-rs 。raft-rs 是 Raft 算法的 R...
摘要:而源碼解析系列文章則是會從源碼層面給大家抽絲剝繭,讓大家知道我們內部到底是如何實現的。我們希望通過該源碼解析系列,能讓大家對有一個更深刻的理解。 作者:唐劉 TiKV 是一個支持事務的分布式 Key-Value 數據庫,有很多社區開發者基于 TiKV 來開發自己的應用,譬如 titan、tidis。尤其是在 TiKV 成為 CNCF 的 Sandbox 項目之后,吸引了越來越多開發者的...
閱讀 699·2021-11-22 09:34
閱讀 3833·2021-09-22 15:42
閱讀 1343·2021-09-03 10:28
閱讀 1084·2021-08-26 14:13
閱讀 1912·2019-08-29 15:41
閱讀 1440·2019-08-29 14:12
閱讀 3376·2019-08-26 18:36
閱讀 3320·2019-08-26 13:47