分布式技術專題-分布式協議算法-帶你徹底認識Paxos算法、Zab協議和Raft協議的原理和本質


內容簡介指南

  • Paxo算法指南

  • Zab算法指南

  • Raft算法指南


Paxo算法指南

Paxos算法的背景

【Paxos算法】是萊斯利·蘭伯特(Leslie Lamport)1990年提出的一種基於消息傳遞的一致性算法,是目前公認的解決分布式一致性問題最有效的算法之一,其解決的問題就是在分布式系統中如何就某個值(決議)達成一致。

Paxos算法的前提

Paxos算法的前提假設是不存在拜占庭將軍問題,即:信道是安全的(信道可靠),發出的信號不會被篡改。

Paxos算法的介紹

在Paxos算法中,有三種角色:

  • proposer:提案Proposal提出者。
  • Acceptor:決策者,可以批准議案。
  • Learner:最終決策的學習者。

Paxos算法安全性前提如下:
  • 只有被提出的value才能被選定。

  • 只有一個value被選定。

  • 如果某個進程認為某個value被選定了,那么這個value必須是真的被選定的那個。

Paxos算法的過程描述:

Paxos算法類似於兩階段提提交,其算法執行過程分為兩個階段。具體如下

prepare階段
  • proposer提出一個編號為N的proposal,發送給半數以上的acceptor
  • acceptor收到編號為N的prepare請求后:
    • 如果小於它已經響應過的請求,則拒絕回復或者回復error;
    • 如果N大於該Acceptor已經響應過的所有Prepare請求的編號,那么它就會將它已經接受過(已經經過第二階段accept的提案)的編號最大的提案(如果有的話,如果還沒有的accept提案的話返回{pok,null,null})作為響應反饋給Proposer,同時存儲更新本地對應的提案編號,並且該Acceptor承諾不再接受任何編號小於N的提案。
    • 分為兩種情況
      • 如果acceptor已經接受過提案,返回接受提案的最大value;
      • 如果還沒有接受過提案,就返回{pok,null,null})
accept階段
  • 如果proposer收到半數以上的acceptor回復的編號為N的提案的prepare響應,那么會發送一個針對[N,V]提案的Accept請求給半數以上的Acceptor。

注意:V就是收到的響應中編號最大的提案的value。

  • 如果響應中不包含任何提案,那么V就由Proposer自己決定,可以是任意值。

  • 如果Acceptor收到一個針對編號為N的提案的Accept請求,只要該Acceptor沒有對編號大於N的Prepare請求做出過響應,它就接受該提案。

  • 如果N小於Acceptor以及響應的prepare請求,則拒絕,不回應或回復error(當proposer沒有收到過半的回應,那么他會重新進入第一階段,遞增提案號,重新提出prepare請求)。

具體如下圖所示:

過半的acceptor都接受提案后,learner會自動感知到,並開始學習提案。(同一個進程可以同時扮演多個角色)

Learner的學習過程

learner學習過程包含兩種場景:
  • Learner所在節點參與了提案選舉,Learner需要知道其接受(accept)的提案值是否被選中(chosen)。
  • Learner所在節點已落后於其他節點,Learner需要選擇合適的策略快速完成追趕,並重新參與到提案選舉當中。
選中通知
  • 本節點Proposer的某個提案被選中(chosen)時,通過(MsgType_PaxosLearner_ProposerSendSuccess)消息通知到各個節點。

  • 正常情況下,所有節點處於online狀態,共同參與paxos選舉。因此為了避免instance id沖突,paxos建議只由主節點的proposer發起提案,這樣保證接受提案和習得提案編號一致。

  • 此時,Learn習得的提案值實際上就是本節點Accept的數據,因此learner只更新內存狀態即可,無需再次落盤(acceptor已落盤)。

  • 最后,如果存在follower節點,數據同步到follower(follower節點不參與paxos算法,相當於某個paxos節點的同步備)。

提案值追趕
  • 一旦節點處於落后狀態,它無法再參與到paxos提案選舉中來。這時需要由learner發起主動學習完成追趕。

  • Paxos啟動時,啟動learner定時器,定時發送learn請求到各個節點,發送請求攜帶本節點的Instance ID、Node ID信息。各節點收到該請求后,回復數據自主完成學習過程。

數據各節點保持數據一致性

為什么要有兩段提交

  • 一方面,第一次預提交后可能被告知已經有觀點了,此時他不應該提出自己的觀點,而應該盡快收斂,支持最新的觀點。
  • 另一方面,進行預加鎖。

怎么保證Proposal編號唯一

  • 假設有K台Server運行paxos算法,那么他們初始編號為0…k-1。以后編號每次增加k,從而保證全局唯一遞增。

  • 正式提案被半數以上Acceptor接受后,就可以確定最終被接受的提案就是該觀點。

  • 兩個半數以上的集合的一定存在交集。

Paxos算法有活鎖問題存在。

介紹了Paxos的算法邏輯,但在算法運行過程中,可能還會存在一種極端情況,當有兩個proposer依次提出一系列編號遞增的議案,那么會陷入死循環,無法完成第二階段,也就是無法選定一個提案。如下圖:

Paxos算法的過半依據

  • 在Paxos算法中,采用了“過半”理念,也就是少數服從多數,這使Paxos算法具有很好的容錯性。那么為什么采用過半就可以呢?
  • Paxos基於的過半數學原理: 我們稱大多數(過半)進程組成的集合為法定集合, 兩個法定(過半)集合必然存在非空交集,即至少有一個公共進程,稱為法定集合性質。 例如A,B,C,D,F進程組成的全集,法定集合Q1包括進程A,B,C,Q2包括進程B,C,D,那么Q1和Q2的交集必然不在空,C就是Q1,Q2的公共進程。如果要說Paxos最根本的原理是什么,那么就是這個簡單性質。也就是說:兩個過半的集合必然存在交集,也就是肯定是相等的,也就是肯定達成了一致。
  • Paxos是基於消息傳遞的具有高度容錯性的分布式一致性算法。Paxos算法引入了過半的概念,解決了2PC,3PC的太過保守的缺點,且使算法具有了很好的容錯性,另外Paxos算法支持分布式節點角色之間的輪換,這極大避免了分布式單點的出現,因此Paxos算法既解決了無限等待問題,也解決了腦裂問題,是目前來說最優秀的分布式一致性算法。其中,Zookeeper的ZAB算法和Raft一致性算法都是基於Paxos的。在后邊的文章中,我會逐步介紹優秀的分布式協調服務框架,也是極優秀的工業一致性算法的實現Zookeeper使用和實現。

ZAB算法指南

Zookeeper 采用的 ZAB協議也是基於 Paxos 算法實現的,不過 ZAB 對 Paxos 進行了很多改進與優化,兩者的設計目標也存在差異——ZAB 協議主要用於構建一個高可用的分布式數據主備系統,而 Paxos 算法則是用於構建一個分布式的一致性狀態機系統。

ZAB協議全稱就是ZooKeeper Atomic Broadcast protocol,是ZooKeeper用來實現一致性的算法,分成如下3個階段

  • fast leader election:快速選舉階段
  • recovery:恢復階段
    • Discovery;
    • Synchrozation
  • broadcasting:廣播階段

先了解一些基本概念

  • electionEpoch:每執行一次leader選舉,electionEpoch就會自增,用來標記leader選舉的輪次
  • peerEpoch:每次leader選舉完成之后,都會選舉出一個新的peerEpoch,用來標記事務請求所屬的輪次
  • zxid:事務請求的唯一標記,由leader服務器負責進行分配高32位是上述的peerEpoch,低32位是請求的計數,從0開始。
  • lastprocessZxid:最后一次commit的事務請求的zxid
  • LinkedList committedLog、long maxCommittedLog、long minCommittedLog:ZooKeeper會保存最近一段時間內執行的事務請求議案,個數限制默認為500個議案。committedLog就是用來保存議案的列表,maxCommittedLog表示最大議案的zxid,minCommittedLog表示committedLog中最小議案的zxid。
  • ConcurrentMap<Long, Proposal> outstandingProposals:Leader擁有的屬性,每當提出一個議案,都會將該議案存放至outstandingProposals,一旦議案被過半認同了,就要提交該議案,則從outstandingProposals中刪除該議案。
  • ConcurrentLinkedQueue toBeApplied:Leader擁有的屬性,每當准備提交一個議案,就會將該議案存放至該列表中,一旦議案應用到ZooKeeper的內存樹中了,然后就可以將該議案從toBeApplied中刪除。
  • state:當前服務器的狀態
  • recvQueue:消息接收隊列,用於存放那些從其他服務器接收到的消息。
  • queueSendMap:消息發送隊列,用於保存那些待發送的消息,按照SID進行分組。
  • senderWorkerMap:發送器集合,每個SenderWorker消息發送器,都對應一台遠程Zookeeper服務器,負責消息的發送,也按照SID進行分組。
  • lastMessageSent:最近發送過的消息,為每個SID保留最近發送過的一個消息。
在ZAB協議中,服務的的狀態state有四種:
  • LOOKING:進入leader選舉狀態
  • FOLLOWING:leader選舉結束,進入follower狀態
  • LEADING:leader選舉結束,進入leader狀態
  • OBSERVING:處於觀察者狀態

協議算法的具體描述

Broadcasting過程
  1. leader針對客戶端的事務請求,創造出一個提案,zxid由leader決定,並將該提案的zxid,提案放到outstandingProposals Map中。
  2. leader向所有的follower發送該提案,如果過半的follower回復OK的話,則leader認為可以提交該議案,則將該議案從outstandingProposals中刪除。
  3. 然后存放到toBeApplied中leader對該議案進行提交,會向所有的follower發送提交該議案的命令,leader自己也開始執行提交過程,會將該請求的內容應用到ZooKeeper的內存樹中。
  4. 然后更新lastProcessedZxid為該請求的zxid,同時將該請求的議案存放到上述committedLog,同時更新maxCommittedLog和minCommittedLog。
  5. leader回復客戶端,並將提案中ToBeApplied中刪除
fast leader election過程

選舉過程關注兩個要點:剛啟動時進行leader選舉和選舉完leader后,剛啟動的server怎么感知到leader,投票過程有兩個比較重要的數據:

  • HashMap<Long, Vote> recvset:用於收集LOOKING、FOLLOWING、LEADING狀態下的server的投票
  • HashMap<Long, Vote> outofelection:用於收集FOLLOWING、LEADING狀態下的server的投票(說明leader選舉已經完成)
具體的過程有:
  1. 服務器先自增electionEpoch,給自己投票:
  • 從快照日志和事務日志中加載數據,得到本機器的內存樹數據,以及lastProcessedZxid。投票內容為:
    • proposedLeader:server自身的myid值,初始為本機器的id
    • proposedZxid:最大事務zxid,初始為本機器的lastProcessedZxid
    • proposedEpoch:peerEpoch值,由上述的lastProcessedZxid的高32得到
    • 然后向所有的服務器發送投票。
  1. server接收到投票通知后,進行PK。

    • 如果收到的通知中的electionEpoch比自己的大,則更新自己的electionEpoch為serverA的electionEpoch;
    • 如果、收到的通知中的electionEpoch比自己的小,則向serverA發送一個通知,將自己的投票以及electionEpoch發送給serverA,serverA收到后就會更新自己的electionEpoch。
    • 如果electionEpoch相同,PK的規則是proposedZxid,然后再是myId
  2. 根據server的狀態來判定leader

    • 如果當前發來的投票的server的狀態是LOOKING狀態,則只需要判斷本機器的投票是否在recvset中過半了,如果過半了則說明leader選舉就算成功了,如果當前server的id等於上述過半投票的proposedLeader,則說明自己將成為了leader,否則自己將成為了follower。

    • 如果當前發來的投票的server的狀態是FOLLOWING、LEADING狀態,則說明leader選舉過程已經完成了,則發過來的投票就是leader的信息,這里就需要判斷發過來的投票是否在recvset或者outofelection中過半了,同時還要檢查leader是否給自己發送過投票信息,從投票信息中確認該leader是不是LEADING狀態。

Recovery過程

一旦leader選舉完成,就開始進入恢復階段,就是follower要同步leader上的數據信息。

  1. 通信初始化

leader會創建一個ServerSocket,接收follower的連接,leader會為每一個連接會用一個LearnerHandler線程來進行服務;

  1. 重新為peerEpoch選舉出一個新的peerEpoch

    • follower會向leader發送一個Leader,FOLLOWERINFO信息,包含自己的peerEpoch信息。

    • leader的LearnerHandler會獲取到上述peerEpoch信息,從中選出一個最大的peerEpoch,然后加1作為新的peerEpoch。

    • 然后leader的所有LearnerHandler會向各自的follower發送一個Leader.LEADERINFO信息,包含上述新的peerEpoch;

    • follower會使用上述peerEpoch來更新自己的peerEpoch,同時將自己的lastProcessedZxid發給leader,leader的根據這個lastProcessedZxid和leader的lastProcessedZxid之間的差異進行同步。

  2. 已經處理的事務議案的同步

    • 判斷LearnerHandler中的lastProcessedZxid是否在minCommittedLog和maxCommittedLog之間

    • LearnerHandler中的lastProcessedZxid和leader的lastProcessedZxid一致,則說明已經保持同步了

    • 如果lastProcessedZxid在minCommittedLog和maxCommittedLog之間,從lastProcessedZxid開始到maxCommittedLog結束的這部分議案,重新發送給該LearnerHandler對應的follower,同時發送對應議案的commit命令。

上述可能存在一個問題:即lastProcessedZxid雖然在他們之間,但是並沒有找到lastProcessedZxid對應的議案,即這個zxid是leader所沒有的,此時的策略就是完全按照leader來同步,刪除該follower這一部分的事務日志,然后重新發送這一部分的議案,並提交這些議案。

  • 如果lastProcessedZxid大於maxCommittedLog,則刪除該follower大於部分的事務日志

  • 如果lastProcessedZxid小於minCommittedLog,則直接采用快照的方式來恢復。

  1. 未處理的事務議案的同步

    • LearnerHandler還會從leader的toBeApplied數據中將大於該LearnerHandler中的lastProcessedZxid的議案進行發送和提交(toBeApplied是已經被確認為提交的)

    • LearnerHandler還會從leader的outstandingProposals中大於該LearnerHandler中的lastProcessedZxid的議案進行發送,但是不提交(outstandingProposals是還沒被被確認為提交的)

  2. 將LearnerHandler加入到正式follower列表中

  3. LearnerHandler發送Leader.NEWLEADER以及Leader.UPTODATE命令。

    • leader開始進入心跳檢測過程,不斷向follower發送心跳命令,不斷檢是否有過半機器進行了心跳回復,如果沒有過半,則執行關閉操作,開始進入leader選舉狀態;
    • LearnerHandler向對應的follower發送Leader.UPTODATE,follower接收到之后,開始和leader進入Broadcast處理過程。

事務持久化和恢復過程

  • 事務持久化分為:broadcasting持久化和leader shutdown過程的持久化。
    • leader針對每次事務請求都會生成一個議案,然后向所有的follower發送該議案。follower收到提案后,將該議案記錄到事務日志中,每當記滿100000個(默認),則事務日志執行flush操作,同時開啟一個新的文件來記錄事務日志
    • 同時會執行內存樹的快照,snapshot.[lastProcessedZxid]作為文件名創建一個新文件,快照內容保存到該文件中
    • 一旦leader過半的心跳檢測失敗,則執行shutdown方法,在該shutdown中會對事務日志進行flush操作
事務的恢復分為快照恢復和日志恢復。
  • 事務快照的恢復:會在事務快照文件目錄下找到最近的100個快照文件,並排序,最新的在前;對上述快照文件依次進行恢復和驗證,一旦驗證成功則退出,否則利用下一個快照文件進行恢復。恢復完成更新最新的lastProcessedZxid;
  • 事務日志的恢復:從事務日志文件目錄下找到zxid大於等於上述lastProcessedZxid的事務日志,然后對上述事務日志進行遍歷,應用到ZooKeeper的內存樹中,同時更新lastProcessedZxid,同時將上述事務日志存儲到committedLog中,並更新maxCommittedLog、minCommittedLog

Raft算法指南

Raft背景

在分布式系統中,一致性算法至關重要。在所有一致性算法中,Paxos 最負盛名,它由萊斯利·蘭伯特(Leslie Lamport)於 1990 年提出,是一種基於消息傳遞的一致性算法,被認為是類似算法中最有效的。

Paxos算法雖然很有效,但復雜的原理使它實現起來非常困難,截止目前,實現 Paxos 算法的開源軟件很少,比較出名的有 Chubby、LibPaxos。


  • 由於Paxos算法過於復雜、實現困難,極大地制約了其應用,而分布式系統領域又亟需一種高效而易於實現的分布式一致性算法,在此背景下,Raft 算法應運而生。

  • Raft是一個共識算法(consensus algorithm),所謂共識,就是多個節點對某個事情達成一致的看法,即使是在部分節點故障、網絡延時、網絡分割的情況下。

  • 共識算法的實現一般是基於復制狀態機(Replicated state machines),何為復制狀態機:簡單來說:相同的初識狀態 + 相同的輸入 = 相同的結束狀態。

Raft 角色

一個Raft集群包含若干個節點,這些節點分為三種狀態:Leader、 Follower、Candidate,每種狀態負責的任務也是不一樣的。正常情況下,集群中的節點只存在 Leader與Follower兩種狀態。

  • leader:負責日志的同步管理,處理來自客戶端的請求,與Follower保持heartBeat的聯系;
  • follower:響應 Leader 的日志同步請求,響應Candidate的邀票請求,以及把客戶端請求到Follower的事務轉發(重定向)給Leader;
  • candidate:負責選舉投票,集群剛啟動或者Leader宕機時,狀態為Follower的節點將轉為Candidate並發起選舉,選舉勝出(獲得超過半數節點的投票)后,從Candidate轉為Leader狀態。

還有一個關鍵概念:term(任期)。以選舉(election)開始,每一次選舉term都會自增,充當了邏輯時鍾的作用。

Raft的3個子問題

為簡化邏輯和實現,Raft 將一致性問題分解成了三個相對獨立的子問題。

  • 選舉(Leader Election):當 Leader 宕機或者集群初創時,一個新的 Leader 需要被選舉出來;
  • 日志復制(Log Replication):Leader 接收來自客戶端的請求並將其以日志條目的形式復制到集群中的其它節點,並且強制要求其它節點的日志和自己保持一致;
  • 安全性(Safety):如果有任何的服務器節點已經應用了一個確定的日志條目到它的狀態機中,那么其它服務器節點不能在同一個日志索引位置應用一個不同的指令。

選舉過程

如果follower在election timeout內沒有收到來自leader的心跳,則會主動發起選舉。

第一階段:所有節點都是 Follower。

Raft 集群在剛啟動(或 Leader 宕機)時,所有節點的狀態都是 Follower,初始 Term(任期)為 0。同時啟動選舉定時器,每個節點的選舉定時器超時時間都在 100~500 毫秒之間且並不一致。

第二階段:Follower 轉為 Candidate 並發起投票。

沒有leader后,followers狀態自動轉為candidate,並向集群中所有節點發送投票請求並且重置選舉定時器。

投票過程有:
  • 增加節點本地的current term ,切換到candidate狀態
  • 投自己一票,並行給其他節點發送 RequestVote RPCs
  • 等待其他節點的回復,可能出現三種結果:
    • 收到majority的投票(含自己的一票),則贏得選舉,成為leader
    • 被告知別人已當選,那么自行切換到follower
    • 一段時間內沒有收到majority投票,則保持candidate狀態,重新發出選舉
第三階段:投票策略
投票的約束條件有:
  • 在一個term內,一個節點只允許發出一次投票;
  • 候選人知道的信息不能比自己的少(這一部分,后面介紹log replication和safety的時候會詳細介紹)
  • first-come-first-served 先來先得
  • 如果參加選舉的節點是偶數個,raft通過randomized election timeouts來盡量避免平票情況,也要求節點的數目都是奇數個,盡量保證majority的出現。

log Replication原理

  • 當leader選舉成功后,客戶端所有的請求都交給了leader,leader調度請求的順序性和followers的狀態一致性。

  • 在集群中,所有的節點都可能變為leader,為了保證后續leader節點變化后依然能夠使集群對外保持一致,需要通過Log Replication機制來解決如下兩個問題:

  • Follower與Leader節點相同的順序依次執行每個成功提案;

  • 每個成功提交的提案必須有足夠多的成功副本,來保證后續的訪問一致

第一階段:客戶端請求提交到 Leader。

Leader 在收到client請求提案后,會將它作為日志條目(Entry)寫入本地log中。需要注意的是,此時該 Entry 的狀態是未提交(Uncommitted),Leader 並不會更新本地數據,因此它是不可讀的。

第二階段:Leader 將 Entry 發送到其它 Follower
  • Leader 與 Floolwers 之間保持着心跳聯系,隨心跳 Leader 將追加的 Entry(AppendEntries)並行地發送給其它的 Follower,並讓它們復制這條日志條目,這一過程稱為復制(Replicate)。

  • 為什么 Leader 向 Follower 發送的 Entry 是 AppendEntries,因為 Leader 與 Follower 的心跳是周期性的,而一個周期間 Leader 可能接收到多條客戶端的請求,因此,隨心跳向 Followers 發送的大概率是多個 Entry,即 AppendEntries。

  • Leader 向 Followers 發送的不僅僅是追加的 Entry(AppendEntries)在發送追加日志條目的時候,Leader 會把新的日志條目緊接着之前條目的索引位置(prevLogIndex), Leader 任期號(Term)也包含在其中。如果 Follower 在它的日志中找不到包含相同索引位置和任期號的條目,那么它就會拒絕接收新的日志條目,因為出現這種情況說明 Follower 和 Leader 不一致。

  • 如何解決 Leader 與 Follower 不一致的問題,正常情況下,Leader 和 Follower 的日志保持一致。然而,Leader 和 Follower 一系列崩潰的情況會使它們的日志處於不一致狀態。

有三種情況:
  1. Follower落后新的leader,丟失一些在新的 Leader 中有的日志條目
  2. Follower領先新的leader,有一些 Leader 沒有的日志條目,
  3. 或者兩者都發生。丟失或者多出日志條目可能會持續多個任期。

要使 Follower 的日志與 Leader 恢復一致,Leader 必須找到最后兩者達成一致的地方(就是回溯,找到兩者最近的一致點),然后刪除從那個點之后的所有日志條目,發送自己的日志給 Follower。Leader 為每一個 Follower 維護一個 nextIndex,它表示下一個需要發送給 Follower 的日志條目的索引地址。當一個 Leader 剛獲得權力的時候,它初始化所有的 nextIndex 值,為自己的最后一條日志的 index 加 1。如果一個 Follower 的日志和 Leader 不一致,那么在下一次附加日志時一致性檢查就會失敗。在被 Follower 拒絕之后,Leader 就會減小該 Follower 對應的 nextIndex 值並進行重試。最終 nextIndex 會在某個位置使得 Leader 和 Follower 的日志達成一致。當這種情況發生,附加日志就會成功,這時就會把 Follower 沖突的日志條目全部刪除並且加上 Leader 的日志。一旦附加日志成功,那么 Follower 的日志就會和 Leader 保持一致,並且在接下來的任期繼續保持一致。

第三階段:Leader 等待 Followers 回應。

Followers 接收到 Leader 發來的復制請求后,有兩種可能的回應:

  • 寫入本地日志中,返回 Success;

  • 一致性檢查失敗,拒絕寫入,返回 False,原因和解決辦法上面已做了詳細說明。

  • 當 Leader 收到大多數 Followers 的回應后,會將第一階段寫入的 Entry 標記為提交狀態(Committed),並把這條日志條目應用到它的狀態機中。

第四階段:Leader 回應客戶端。

完成前三個階段后,Leader會向客戶端回應 OK,表示寫操作成功。

第五階段,Leader 通知 Followers Entry 已提交

Leader 回應客戶端后,將隨着下一個心跳通知 Followers,Followers 收到通知后也會將 Entry 標記為提交狀態。至此,Raft 集群超過半數節點已經達到一致狀態,可以確保強一致性。

raft safety保證

1) election safety: 在一個term內,至多有一個leader被選舉出來。raft算法通過

一個節點某一任期內最多只能投一票;
只有獲得majority投票的節點才會成為leader。
2)log matching:說如果兩個節點上的某個log entry的log index相同且term相同,那么在該index之前的所有log entry應該都是相同的。leader在某一term的任一位置只會創建一個log entry,且log entry是append-only。

3)consistency check。leader在AppendEntries中包含最新log entry之前的一個log 的term和index,如果follower在對應的term index找不到日志,那么就會告知leader不一致。當出現了leader與follower不一致的情況,leader強制follower復制自己的log。

3)leader completeness :如果一個log entry在某個任期被提交(committed),那么這條日志一定會出現在所有更高term的leader的日志里面。

一個日志被復制到majority節點才算committed
一個節點得到majority的投票才能成為leader,而節點A給節點B投票的其中一個前提是,B的日志不能比A的日志舊。
4)stale leader: 落后的leader,但在網絡分割(network partition)的情況下,可能會出現兩個leader,但兩個leader所處的任期是不同的。而在raft的一些實現或者raft-like協議中,leader如果收不到majority節點的消息,那么可以自己step down,自行轉換到follower狀態。

5)leader crash:新的節點成為Leader,為了不讓數據丟失,希望新Leader包含所有已經Commit的Entry。為了避免數據從Follower到Leader的反向流動帶來的復雜性,Raft限制新Leader一定是當前Log最新的節點,即其擁有最多最大term的Log Entry。

6)State Machine Safety

某個leader選舉成功之后,不會直接提交前任leader時期的日志,而是通過提交當前任期的日志的時候“順手”把之前的日志也提交了,具體的實現是:如果leader被選舉后沒有收到客戶端的請求呢,論文中有提到,在任期開始的時候發立即嘗試復制、提交一條空的log。

總結:raft將共識問題分解成兩個相對獨立的問題,leader election,log replication。流程是先選舉出leader,然后leader負責復制、提交log(log中包含command)

log replication約束:

一個log被復制到大多數節點,就是committed,保證不會回滾
leader一定包含最新的committed log,因此leader只會追加日志,不會刪除覆蓋日志
不同節點,某個位置上日志相同,那么這個位置之前的所有日志一定是相同的
Raft never commits log entries from previous terms by counting replicas.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM