zookeeper ZAB協(xié)議的實(shí)現(xiàn)

zookeeper源碼分析系列 中按照服務(wù)端客戶端啟動(dòng)或交互等主線講解了源碼,但并沒有將Zab協(xié)議的完整實(shí)現(xiàn)串起來。本文主要翻譯自ZooKeeper’s atomic broadcast protocol:
Theory and practice
這篇論文,可完整的展現(xiàn)Zab協(xié)議的理論和實(shí)現(xiàn)。
Zab協(xié)議是zookeeper原子廣播協(xié)議,依賴它選舉出一個(gè)Leader同步節(jié)點(diǎn)通過Leader按順序廣播修改內(nèi)容并且從故障中快速恢復(fù)正常狀態(tài)。在介紹上述實(shí)現(xiàn)之前,我們先了解下Zab協(xié)議的背景和協(xié)議的理論知識(shí)。

Paxos協(xié)議和Zab協(xié)議的異同點(diǎn)

原子廣播協(xié)議的重點(diǎn)在于通過leader進(jìn)程原子的順序廣播到其他節(jié)點(diǎn)進(jìn)程,同時(shí)保證這個(gè)操作一致性的成功或者失敗,最終不會(huì)出現(xiàn)節(jié)點(diǎn)之間狀態(tài)不一致的情況。滿足四個(gè)特性:

  • Validity:如果一個(gè)正常的節(jié)點(diǎn)廣播了一個(gè)消息,則所有正常的其他節(jié)點(diǎn)都會(huì)最終提交。
  • Uniform Agreement:如果一個(gè)節(jié)點(diǎn)提交了一個(gè)消息,則所有正常的其他節(jié)點(diǎn)都會(huì)最終提交。
  • Uniform Integrity:對(duì)任何消息,每個(gè)節(jié)點(diǎn)最多提交一次,并且先前必須廣播過。
  • Uniform Total Order:如果節(jié)點(diǎn)q和p提交兩個(gè)消息m和m',則q和p對(duì)消息m和m'的提交順序應(yīng)是一樣的。
    Paxos是解決分布式共識(shí)(分布式一致性)的協(xié)議。它的目的不在于原子廣播,當(dāng)然它可以對(duì)原子廣播的協(xié)議提供支持,如Zab協(xié)議。但是它不對(duì)上述原子廣播中的特性提供保證,如所有節(jié)點(diǎn)的一致性順序提交。它只是一個(gè)達(dá)成分布式共識(shí)的算法。
    Zab協(xié)議兩個(gè)重要的要求是提供處理大量的客戶端請(qǐng)求從崩潰中快速恢復(fù)的能力。這種并發(fā)按順序的提交是通過zookeeper內(nèi)部的FIFO隊(duì)列實(shí)現(xiàn)的,同時(shí)對(duì)崩潰恢復(fù)也是有作用的。經(jīng)典的Paxos算法不能滿足處理大量的客戶端請(qǐng)求的要求,因?yàn)?strong>Paxos算法不要求使用FIFO通道通信,所以它允許消息的丟失和亂序提交。在主節(jié)點(diǎn)崩潰后,Paxos不能利用事務(wù)的順序序列來恢復(fù)集群,而Zab協(xié)議通過事務(wù)標(biāo)示(zxid)來表示事務(wù)的順序性, 這樣在選舉時(shí)會(huì)優(yōu)先考慮zxid最高的節(jié)點(diǎn)作為L(zhǎng)eader節(jié)點(diǎn),這樣可使用Leader節(jié)點(diǎn)的提交記錄來同步其他節(jié)點(diǎn)。而在Paxos中節(jié)點(diǎn)同步時(shí),Leader節(jié)點(diǎn)還需要提交所有先前自己為提交的事務(wù)。
    ZooKeeper還需要滿足一些性能要求:如低延遲,高吞吐,一定的容錯(cuò)性等。

崩潰恢復(fù)模型

有選舉權(quán)的節(jié)點(diǎn)叫做peer節(jié)點(diǎn),假設(shè)共有N個(gè)peer節(jié)點(diǎn) (Π= {fp1, p2.. pN}),如果其中大于N/2的peer節(jié)點(diǎn)投票的leader節(jié)點(diǎn)是同一個(gè)( Q> N=2,Q ? Π),則選主完成,這組peer節(jié)點(diǎn)稱為一個(gè)quorum。每個(gè)peer節(jié)點(diǎn)兩兩建立雙向通道,從而保證:

  • Integrity:節(jié)點(diǎn)p從特定通道接收到的消息一定是另一端節(jié)點(diǎn)發(fā)送的。
  • Prefix:節(jié)點(diǎn)p從特定通道接收到的消息順序一定是另一段節(jié)點(diǎn)發(fā)送的消息順序。ZooKeeper使用tcp通信的先進(jìn)先出通道來實(shí)現(xiàn)。

Zab協(xié)議的滿足特性

為了實(shí)現(xiàn)一致性保證,Zab協(xié)議必須滿足一些特性。首先先聲明下一些協(xié)議定義。
ZooKeeper中需要保證事務(wù)的順序性,所以同一時(shí)刻只能有一個(gè)leader節(jié)點(diǎn)。我們定義leader節(jié)點(diǎn)的變化為ρ1ρ2 ... ρe....(ρe ? Π),其中e代表一個(gè)整數(shù)epoch,表示在這個(gè)周期內(nèi)ρe是這組集群的leader節(jié)點(diǎn)。此外如果e < e',則 ρe節(jié)點(diǎn)不是祝節(jié)點(diǎn),ρe'才是。
事務(wù)代表的是leader節(jié)點(diǎn)向其他節(jié)點(diǎn)廣播的新狀態(tài),用<v,z>表示。其中v代表新狀態(tài)的內(nèi)容,z代表zxid。事務(wù)的提交是兩階段提交,首先leader節(jié)點(diǎn)發(fā)送事務(wù)的 proposal,得到超過一半的peer節(jié)點(diǎn)的ack之后,再發(fā)送commit給所有節(jié)點(diǎn)。下面這些特性Zab協(xié)議必須滿足:

  • Integrity:如果節(jié)點(diǎn)提交<v,z>事務(wù),則節(jié)點(diǎn)一定收到過事務(wù)的proposal
  • Total order:如果一些節(jié)點(diǎn)先提交<v,z>,后提交<v',z'>,則其他任何節(jié)點(diǎn)也是這個(gè)提交順序。
  • Agreement:就是說一個(gè)事務(wù)要么成功,要么失敗。且成功的內(nèi)容所有節(jié)點(diǎn)都是一樣的。
    每個(gè)集群節(jié)點(diǎn)的事務(wù)一致性順序性(Primary order)需要滿足:
  • Local primary order:如果 leader節(jié)點(diǎn)上<v,z>先于<v',z'>廣播,則<v,z>,先于<v',z'>提交。
  • Global primary order:如果epoch i<i',ρi節(jié)點(diǎn)廣播了<v,z>,ρi'節(jié)點(diǎn)廣播了<v',z'>,如果均提交的話,則<v,z>,先于<v',z'>提交。
  • Primary integrity:如果epoch i<i',ρi節(jié)點(diǎn)廣播了<v,z>并且有些節(jié)點(diǎn)提交了<v',z'>,則<v,z>的提交要先于<v',z'>的廣播。

Local primary order是由節(jié)點(diǎn)本地FIFO隊(duì)列實(shí)現(xiàn)的,Primary integrity保證了新的epoch的前epoch事務(wù)都已經(jīng)提交了。

Zab協(xié)議的理論實(shí)現(xiàn)

在Zab協(xié)議中,一個(gè)peer節(jié)點(diǎn)可能有三種狀態(tài):

  • following
  • leading
  • electing
    同時(shí),一個(gè)peer節(jié)點(diǎn)對(duì)應(yīng)ZooKeeper中的三種執(zhí)行階段:
    Phase1:discovery
    此時(shí)peer節(jié)點(diǎn)處于electing狀態(tài),正在投票選舉出一個(gè)leader節(jié)點(diǎn)出來,同時(shí)確定自己的節(jié)點(diǎn)狀態(tài)。有時(shí)集群選舉也叫做Phase0階段。
    Phase2:synchronization
    leader節(jié)點(diǎn)和其他節(jié)點(diǎn)數(shù)據(jù)同步。
    Phase3:broadcast
    Phase3階段完成了過半peer節(jié)點(diǎn)的數(shù)據(jù)一致性同步,此階段至多有一個(gè)leader節(jié)點(diǎn)用來廣播原子事務(wù)消息,類似于兩階段提交。Phase1和Phase2對(duì)于集群整體數(shù)據(jù)一致性至關(guān)重要,特別是在崩潰回復(fù)時(shí)。在這三個(gè)階段中,如果peer節(jié)點(diǎn)有節(jié)點(diǎn)間通信失敗或者超時(shí)發(fā)生,peer節(jié)點(diǎn)可決定是否回到Phase0階段重新選舉。
    ZooKeeper客戶端通常和一個(gè)ZooKeeper服務(wù)端節(jié)點(diǎn)建立會(huì)話連接,如果是寫請(qǐng)求,ZooKeeper節(jié)點(diǎn)會(huì)將請(qǐng)求轉(zhuǎn)發(fā)給leader節(jié)點(diǎn),讀請(qǐng)求的話則節(jié)點(diǎn)自己處理。客戶端可發(fā)送sync請(qǐng)求是建立連接的節(jié)點(diǎn)數(shù)據(jù)副本和leader節(jié)點(diǎn)保持一致。

Zab協(xié)議中zxid對(duì)total order 特性至關(guān)重要。一個(gè)事務(wù)<v,z>中的z(zxid)由兩部分構(gòu)成,記為<e,c>。其中 e 為發(fā)出當(dāng)前事務(wù)的leader節(jié)點(diǎn)的epoch, c 是自增整數(shù)計(jì)數(shù)器。當(dāng)一個(gè)新的選舉周期epoch產(chǎn)生時(shí),一個(gè)新的leader節(jié)點(diǎn)被激活,c 從0開始遞增,而 e 在原來epoch值的基礎(chǔ)上遞增。因此,事務(wù)的順序由它們的zxid保證。對(duì)于兩個(gè)zxid <e,c><e',c'>,如果 <e,c> < <e',c'>,則e < e' or (if e = e' and c < c')

對(duì)于一個(gè)peer節(jié)點(diǎn),有四個(gè)重要的屬性影響著它的節(jié)點(diǎn)狀態(tài),在各個(gè)執(zhí)行階段均有所作用。

history:最新log文件中接受的事務(wù)proposals
acceptedEpoch:最近一次接收到的NEWEPOCH消息的epoch值( 可看作最近一次的選舉epoch值,當(dāng)選舉結(jié)束進(jìn)入phase2時(shí),leader節(jié)點(diǎn)acceptedEpoch=currentEpoch+1;進(jìn)入phase3時(shí),各節(jié)點(diǎn)acceptedEpoch=currentEpoch)
currentEpoch:最近一次接收到的NEWLEADER消息的epoch值(可看作最近一次廣播階段的epoch)
lastZxid:history中最大的zxid值

Phase0:Leader election

這階段peer節(jié)點(diǎn)進(jìn)行初始化(會(huì)初始化上面四個(gè)屬性),節(jié)點(diǎn)狀態(tài)為electing。當(dāng)集群獲得一個(gè)quorum節(jié)點(diǎn)集合的一致投票時(shí),leader節(jié)點(diǎn)就被選出了。每個(gè)peer節(jié)點(diǎn)會(huì)將這個(gè)選票保存到內(nèi)存volatile變量中。如果leader選票節(jié)點(diǎn)是自己,增更新狀態(tài)為leading,否則為following。

Phase1:Discovery

這階段其他節(jié)點(diǎn)主動(dòng)和leader節(jié)點(diǎn)建立連接,leader節(jié)點(diǎn)可以收集follower節(jié)點(diǎn)的最近事務(wù)信息。這個(gè)階段的目的是在一個(gè)quorum中發(fā)現(xiàn)最新接收的proposal,并且確定新一輪的epoch,從而使之前的leader無法原子廣播事務(wù)


如果這期間的主從連接出現(xiàn)斷掉,follower節(jié)點(diǎn)會(huì)重新回到Phase0階段。

Phase2:Synchronization

同步階段是使集群節(jié)點(diǎn)的副本數(shù)據(jù)狀態(tài)統(tǒng)一更新為Phase1中l(wèi)eader節(jié)點(diǎn)的數(shù)據(jù)狀態(tài)。leader節(jié)點(diǎn)首先將自己的history發(fā)送給各個(gè)節(jié)點(diǎn),當(dāng)leader接收到一個(gè)quorum的ack之后,leader會(huì)發(fā)送commit消息給各個(gè)節(jié)點(diǎn)。從而leader節(jié)點(diǎn)真正建立了。


Phase3:Broadcast

如果不發(fā)生崩潰,peers節(jié)點(diǎn)將永遠(yuǎn)待在這個(gè)狀態(tài),并開啟對(duì)客戶端的服務(wù)提供。由leader節(jié)點(diǎn)負(fù)責(zé)客戶端的寫入請(qǐng)求的原子廣播。同時(shí),leader節(jié)點(diǎn)也允許新的follower節(jié)點(diǎn)加入這個(gè)epoch中。


算法1,2,3是異步的并且沒有考慮可能的節(jié)點(diǎn)崩潰情況。Zab協(xié)議通過主從節(jié)點(diǎn)周期性的心跳消息來檢測(cè)節(jié)點(diǎn)的崩潰異常。如果leader節(jié)點(diǎn)沒有在心跳時(shí)間內(nèi)收到一個(gè)quorum集合的心跳,則放棄自己的lead權(quán)限并回到Phase0階段。如果follower在在心跳時(shí)間內(nèi)沒有收到leader節(jié)點(diǎn)的心跳,也同樣回到Phase0階段重新選舉。

Zab協(xié)議算法分析

從上面三個(gè)算法中,可以得出一些不變性:

  • 在phase3階段,一個(gè)從節(jié)點(diǎn)接收一個(gè)proposal <e,<v,z>>只有當(dāng)它當(dāng)前的currentEpoch=e才行。
  • 在一個(gè)epoch=e的phase3階段,只有從節(jié)點(diǎn)的currentEpoch=e才能根據(jù)zxid的順序接收事務(wù)的proposal和commit。
  • 在phase1階段,從節(jié)點(diǎn)不會(huì)接收比自己的acceptEpoch小的任何周期的leader的proposal。
  • 在phase1階段,ACKEPOCH(F.currentEpoch,F.history,F.lastZxid)消息中F.history的事務(wù)不會(huì)改變,重排序或丟失。在phase2階段,NEWLEADER(e',L.history)消息中,L.history的事務(wù)不會(huì)改變,重排序或丟失。
  • 在phase3階段,從節(jié)點(diǎn)提交的事務(wù)順序就是當(dāng)前l(fā)eader節(jié)點(diǎn)廣播并提交的事務(wù)順序。
    同樣可得出一些聲明:
  • 在每個(gè)周期epoch e內(nèi),在phase3階段只能???一個(gè)進(jìn)程調(diào)用ready(e)
  • Zab協(xié)議滿足我們上面提到的broadcast integrity, agreement, total order, local primary order, global primary order, and primary integrity特性。
  • Liveness property:如果位于Quorum中的主從節(jié)點(diǎn)均是正常通信狀態(tài),則leader節(jié)點(diǎn)發(fā)送的事務(wù)proposal和commit消息,位于Quorum中的從節(jié)點(diǎn)會(huì)及時(shí)收到并且作出對(duì)應(yīng)的狀態(tài)修改。

ZooKeeper中Zab協(xié)議的具體實(shí)現(xiàn)

首先需要明白ZooKeeper節(jié)點(diǎn)之間的FIFO順序通信Zab協(xié)議的保證,本文大致基于ZooKeeper 3.3.4的版本進(jìn)行分析。ZooKeeper對(duì)Zab協(xié)議的實(shí)現(xiàn)大體遵循上面的算法1,2,3,此外會(huì)有一些算法優(yōu)化導(dǎo)致具體實(shí)現(xiàn)有所不同。
在ZooKeeper中,默認(rèn)實(shí)現(xiàn)的選舉算法是Fast Leader Election(FLE),其中Phase0和Phase1階段是緊緊耦合在一起的。這個(gè)算法的優(yōu)化在于:它嘗試在集群選舉中從quorum節(jié)點(diǎn)中選出擁有最新history的節(jié)點(diǎn)作為leader節(jié)點(diǎn),這樣在phase1階段leader節(jié)點(diǎn)不需要和其他從節(jié)點(diǎn)通信來發(fā)現(xiàn)最新的history了。在FLE的實(shí)現(xiàn)中,Phase1階段的部分功能可省略,我們將Phase1和Phase2階段合并為Recovery Phase。對(duì)比zab協(xié)議的階段劃分,zookeeper中具體階段實(shí)現(xiàn)為:


接下來我們將看下zookeeper中這些階段的具體實(shí)現(xiàn)。

Recovery Phase


Recovery Phase更多的用來做phase2階段的同步工作。
從節(jié)點(diǎn)連接leader節(jié)點(diǎn),并發(fā)送FOLLOWERINFO(F.lastZxid)消息給leader節(jié)點(diǎn),這樣leader節(jié)點(diǎn)可以決定和從節(jié)點(diǎn)的同步方式。這里數(shù)據(jù)同步時(shí)和phase2階段的不同是:如果從節(jié)點(diǎn)接收到了TRUNC消息,這里從節(jié)點(diǎn)可丟失掉比leader節(jié)點(diǎn)還大的事務(wù),如果從節(jié)點(diǎn)接收到了DIFF消息,這里從節(jié)點(diǎn)可只接收leader節(jié)點(diǎn)上自己沒有的事務(wù)消息。
這些特性是由history.lastCommitedZxid(history中最新提交的zxid)和history.oldThreshold(history中保存的最老的提交zxid)保證的。

同步的目的是使得所有節(jié)點(diǎn)上的副本數(shù)據(jù)和主節(jié)點(diǎn)保持一致。所以leader節(jié)點(diǎn)上已提交的事務(wù)必須按同樣的順序同步到所有其他節(jié)點(diǎn),未提交的proposal(包括所有節(jié)點(diǎn)上比leader.history.lastCommitedZxid大的proposal)必須拋棄掉使得所有節(jié)點(diǎn)都不會(huì)提交。SNAPDIFF消息保證提交不丟失,TRUNC消息保證未提交proposal被丟棄掉。

這里如果zookeeper并沒有區(qū)分acceptedEpoch和currentEpoch,從節(jié)點(diǎn)會(huì)從history.lastCommitedZxid 中獲得current epoch,如果F嘗試連接的本地prospective leader L不是leading狀態(tài),則L會(huì)拒絕連接,F(xiàn)會(huì)執(zhí)行22行。

Fast Leader Election

FLE算法是Recovery Phase的重要保證,它嘗試保證leader節(jié)點(diǎn)擁有所有歷史提交的事務(wù),基于如果一個(gè)peer節(jié)點(diǎn)有最新的proposal(lastZxid),那么它同樣擁有最新的commit這樣一個(gè)假設(shè)。
下面我們將看一下FLE的實(shí)現(xiàn)細(xì)節(jié)。選舉過程中peer節(jié)點(diǎn)相互交換自己的選票,期間如果接收到更新的選票則更新自己的選票,最終從一個(gè)quorum節(jié)點(diǎn)中選出一個(gè)leader。選票結(jié)束時(shí),每個(gè)peer節(jié)點(diǎn)會(huì)根據(jù)選票結(jié)果確定自己是leader還是follower。期間出現(xiàn)異常會(huì)導(dǎo)致peer節(jié)點(diǎn)回到electing狀態(tài)并重新選舉,新一輪FLE的開始會(huì)導(dǎo)致選舉輪次自增(選舉輪次只是用來標(biāo)記本節(jié)點(diǎn)收到的選票是在第幾輪,leader節(jié)點(diǎn)的選舉是同處在選舉狀態(tài)的節(jié)點(diǎn)在同一個(gè)輪次中誕生的。選舉開始時(shí)選舉輪次的值為currentEpoch)。
其中如何確定誰的選票最大呢?假設(shè)有N個(gè)peer節(jié)點(diǎn),peer節(jié)點(diǎn) pi 的選票為用<zi,i>表示,其中 zi 代表 pi 上最新proposal的zxid(即lastZxid),i 代表節(jié)點(diǎn)的的server id(在集群中是唯一的,就是zookeeper中的myid)。如果<zi,i> > <zi',i'>則滿足zi > zi' or (zi = zi' and i>i')。這樣可保證當(dāng)選舉結(jié)束時(shí),從節(jié)點(diǎn)自己的選票票值是小于主節(jié)點(diǎn)的。

在FLE選舉過程中,是沒有將變量狀態(tài)持久化到磁盤的。這意味著FLE的選舉輪次是沒有持久化的。選舉過程中使用了持久化的變量lastZxid,其中沒有持久化的重要變量有選票vote,選舉狀態(tài)state,當(dāng)前選舉輪次round,identification number(id)和接收選票的隊(duì)列內(nèi)容。對(duì)于zookeeper來說,發(fā)送給其他peer節(jié)點(diǎn)的選舉投票消息是notification消息,包括(vote, id, state, round)這些信息。完整的算法偽代碼為:


每個(gè)peer節(jié)點(diǎn)都知道所有的peer節(jié)點(diǎn)地址和總的peer節(jié)點(diǎn)數(shù)目SizeEnsemble。一開始peer節(jié)點(diǎn)會(huì)投票給自己,然后將notification發(fā)送給其他peer節(jié)點(diǎn),等待其他peer節(jié)點(diǎn)的notifications。當(dāng)接收到其他的peer節(jié)點(diǎn)的notifications時(shí),會(huì)根據(jù)
它們的notification中的state來處理這些選票
。如果收到的選票state是electing狀態(tài),位于相同輪次round的選票會(huì)進(jìn)行選票大小比較,并將本節(jié)點(diǎn)選票更新為比自己大的選票。輪次round比自己的輪次小的選票會(huì)被忽略掉。如果選舉輪次比自己大,說明本節(jié)點(diǎn)的選舉輪次是落后的,應(yīng)該清空當(dāng)前收到的所有選票信息,并更新自己的選舉輪次,再比較選票大小。如果收到的選票state是following或leading狀態(tài),同樣會(huì)根據(jù)輪次判斷怎么處理選票。如果是相同輪次的選票,則將當(dāng)前輪次的選票放在一起,看是否能選出一個(gè)quorum,確定出leader,如果可以再確定自己的state狀態(tài)并結(jié)束選舉。如果是不同輪次的選票,將選票放在外部的選票集合中(因?yàn)榇藭r(shí)可能處于當(dāng)前節(jié)點(diǎn)崩潰,但集群仍正常可用的狀態(tài)),并收集所有外部選票,如果能選出一個(gè)quorum,確定出leader,并確定自己的state狀態(tài)結(jié)束選舉。

算法中有幾個(gè)需要注意的點(diǎn):

  • DeduceLeader(id):從quorum中確定leader節(jié)點(diǎn)是誰時(shí),需要根據(jù)leader節(jié)點(diǎn)信息確定出自己的state狀態(tài)。
  • Put(Table(id), vote, round):收集來自其他peer節(jié)點(diǎn)的選票set集合,key為server id。
  • Notifications Receiver:會(huì)有一個(gè)專門的線程負(fù)責(zé)接收其他節(jié)點(diǎn)的Notifications,并依次放到fifo隊(duì)列中并傳遞到FLE選舉過程中。并且比較選票之后,發(fā)出自己的最新選票給其他peer節(jié)點(diǎn)。

ZooKeeper實(shí)現(xiàn)Zab協(xié)議中的問題

這里主要討論兩個(gè)問題。
1.節(jié)點(diǎn)在Recovery PhaseFLE之間循環(huán)
ZooKeeper 3.3.3版本沒有區(qū)分acceptedEpochcurrentEpoch,會(huì)可能導(dǎo)致節(jié)點(diǎn)在Recovery PhaseFLE之間循環(huán)。當(dāng)一個(gè)peer節(jié)點(diǎn)內(nèi)部選票達(dá)成一致,并稱為leader(稱為proposal leader)時(shí),運(yùn)行到Algorithm4 的第4行,將自己的lastZxid發(fā)送給其他follower節(jié)點(diǎn)(注意Algorithm4 的第2行此時(shí)leader將epoch遞增了,lastZxid也會(huì)更新epoch)。因?yàn)楫?dāng)follower節(jié)點(diǎn)的lastZxid.epoch大于leader節(jié)點(diǎn)的lastZxid.epoch時(shí),將會(huì)重新回到electing狀態(tài)(Algorithm4 的第25行)。當(dāng)proposal leader節(jié)點(diǎn)出現(xiàn)異常并放棄自己的領(lǐng)導(dǎo)權(quán)限并且成為之前epoch選舉出來的新leader的follower時(shí),便會(huì)出現(xiàn)Algorithm4 的第25行的情況。此時(shí)這個(gè)原來的proposal leader節(jié)點(diǎn)便會(huì)在Recovery PhaseFLE之間循環(huán)。

產(chǎn)生這個(gè)問題的原因就是peer節(jié)點(diǎn)用lastZxid來記錄epoch值,并不能區(qū)分出來最新選舉過程中的epoch認(rèn)定的最新leader的epoch,因此定義了acceptedEpochcurrentEpoch。這樣在Algorithm4 的第25行便可通過proposal leader節(jié)點(diǎn)的新的epoch(在acceptedEpoch的基礎(chǔ)上加1)和follower的acceptedEpoch做比較,前者一定大于后者,從而避免循環(huán)。

2.丟掉follower節(jié)點(diǎn)proposal事務(wù)
Algorithm4假設(shè)第11行當(dāng)follower.lastZxid>L.history.lastCommittedZxid時(shí),leader節(jié)點(diǎn)就發(fā)送TRUNC消息使follower節(jié)點(diǎn)丟掉L.history.lastCommittedZxid之后的proposal,但有時(shí)follower節(jié)點(diǎn)可能存在L.history.lastCommittedZxid之前的應(yīng)丟棄的proposal。(參考issue ZOOKEEPER-1154)。下面將考慮導(dǎo)致這個(gè)問題的一種場(chǎng)景:

假設(shè)有三個(gè)peer節(jié)點(diǎn)p1,p2,p3,此時(shí)處于廣播階段,p1是leader節(jié)點(diǎn)且所有peer節(jié)點(diǎn)都處于正常工作狀態(tài)。此時(shí)它們均同步一致并提交了zxid <e = 1,c = 3>事務(wù),p1節(jié)點(diǎn)接收并創(chuàng)建了新的事務(wù)zxid <e = 1,c = 4>,但還沒有將這個(gè)proposal發(fā)給p2,p3便掛掉了。p2,p3經(jīng)過重新選舉,p2成為新的leader節(jié)點(diǎn),并且成功進(jìn)入廣播狀態(tài),提交事務(wù)到zxid <e = 2,c = 1>,并且p2.history.oldThreshold = <1,1>。此時(shí)p1節(jié)點(diǎn)重新處于正常工作狀態(tài),會(huì)成為p2的follower節(jié)點(diǎn)。在p1的Recovery階段,p1會(huì)給p2發(fā)送FOLLOWERINFO(p1.lastZxid = <1, 4>)消息,因?yàn)? p2.history.oldThreshold (1,1) <1, 4> < p2.history.lastCommittedZxid (<2,1>),按照Algorithm4此時(shí)p2會(huì)給p1發(fā)送DIFF請(qǐng)求進(jìn)行差異同步。但是 <1, 4>只存在于p1節(jié)點(diǎn)上,應(yīng)該被丟棄掉。

對(duì)于這種場(chǎng)景,p2可發(fā)送TRUNC消息使p1丟棄掉 <1, 4>,或者p2可發(fā)送SNAP消息使p1全量同步自己的數(shù)據(jù)。ZooKeeper采用的后一種方式來解決這個(gè)問題。

感謝您的閱讀,我是Monica23334 || Monica2333 。立下每周寫一篇原創(chuàng)文章flag的小姐姐,關(guān)注我并期待打臉吧~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,595評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,560評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,814評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,224評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,444評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,988評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,804評(píng)論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,998評(píng)論 1 370
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評(píng)論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,237評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評(píng)論 1 287
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,706評(píng)論 3 393
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,993評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容