一. 核心工作原理,ZAB協定?
ZAB協定是為分布式協調服務Zookeeper專門設計的一種支援崩潰恢複的原子廣播協定(paxos算法的一種實作)。
ZAB協定包括兩種基本的模式:崩潰恢複和消息廣播。
當整個zookeeper叢集剛剛啟動或者Leader伺服器當機、重新開機或者網絡故障導緻不存在過半的伺服器與Leader伺服器保持正常通信時,所有程序(伺服器)進入崩潰恢複模式,首先選舉産生新的Leader伺服器,然後叢集中Follower伺服器開始與新的Leader伺服器進行資料同步,當叢集中超過半數機器與該Leader伺服器完成資料同步之後,退出恢複模式進入消息廣播模式,Leader伺服器開始接收用戶端的事務請求生成事物提案來進行事務請求處理。
二. Leader選舉流程?
Leader選舉是保證分布式資料一緻性的關鍵所在。當Zookeeper叢集中的一台伺服器出現以下兩種情況之一時,需要進入Leader選舉:伺服器初始化啟動+伺服器運作期間無法和Leader保持連接配接。
1. 伺服器啟動時期的Leader選舉
若進行Leader選舉,則至少需要兩台機器,這裡選取3台機器組成的伺服器叢集為例。在叢集初始化階段,當有一台伺服器Server1啟動時,其單獨無法進行和完成Leader選舉,當第二台伺服器Server2啟動時,此時兩台機器可以互相通信,每台機器都試圖找到Leader,于是進入Leader選舉過程。選舉過程如下
(1) 每個Server發出一個投票。由于是初始情況,Server1和Server2都會将自己作為Leader伺服器來進行投票,每次投票會包含所推舉的伺服器的myid和ZXID,使用(myid, ZXID)來表示,此時Server1的投票為(1, 0),Server2的投票為(2, 0),然後各自将這個投票發給叢集中其他機器。
(2) 接受來自各個伺服器的投票。叢集的每個伺服器收到投票後,首先判斷該投票的有效性,如檢查是否是本輪投票、是否來自LOOKING狀态的伺服器。
(3) 處理投票。針對每一個投票,伺服器都需要将别人的投票和自己的投票進行PK,PK規則如下
· 優先檢查ZXID。ZXID比較大的伺服器優先作為Leader。
· 如果ZXID相同,那麼就比較myid。myid較大的伺服器作為Leader伺服器。
對于Server1而言,它的投票是(1, 0),接收Server2的投票為(2, 0),首先會比較兩者的ZXID,均為0,再比較myid,此時Server2的myid最大,于是更新自己的投票為(2, 0),然後重新投票,對于Server2而言,其無須更新自己的投票,隻是再次向叢集中所有機器發出上一次投票資訊即可。
(4) 統計投票。每次投票後,伺服器都會統計投票資訊,判斷是否已經有過半機器接受到相同的投票資訊,對于Server1、Server2而言,都統計出叢集中已經有兩台機器接受了(2, 0)的投票資訊,此時便認為已經選出了Leader。
(5) 改變伺服器狀态。一旦确定了Leader,每個伺服器就會更新自己的狀态,如果是Follower,那麼就變更為FOLLOWING,如果是Leader,就變更為LEADING。
2. 伺服器運作時期的Leader選舉
在Zookeeper運作期間,Leader與非Leader伺服器各司其職,即便當有非Leader伺服器當機或新加入,此時也不會影響Leader,但是一旦Leader伺服器挂了,那麼整個叢集将暫停對外服務,進入新一輪Leader選舉,其過程和啟動時期的Leader選舉過程基本一緻。假設正在運作的有Server1、Server2、Server3三台伺服器,目前Leader是Server2,若某一時刻Leader挂了,此時便開始Leader選舉。選舉過程如下
(1) 變更狀态。Leader挂後,餘下的非Observer伺服器都會講自己的伺服器狀态變更為LOOKING,然後開始進入Leader選舉過程。
(2) 每個Server會發出一個投票。在運作期間,每個伺服器上的ZXID可能不同,此時假定Server1的ZXID為123,Server3的ZXID為122;在第一輪投票中,Server1和Server3都會投自己,産生投票(1, 123),(3, 122),然後各自将投票發送給叢集中所有機器。
(3) 接收來自各個伺服器的投票。與啟動時過程相同。
(4) 處理投票。與啟動時過程相同,此時,Server1将會成為Leader。
(5) 統計投票。與啟動時過程相同。
(6) 改變伺服器的狀态。與啟動時過程相同。
3. Leader選舉算法分析
在3.4.0後的Zookeeper的版本隻保留了TCP版本的FastLeaderElection選舉算法。當一台機器進入Leader選舉時,目前叢集可能會處于以下兩種狀态
· 叢集中已經存在Leader。
· 叢集中不存在Leader。
對于叢集中已經存在Leader而言,此種情況一般都是某台機器啟動得較晚,在其啟動之前,叢集已經在正常工作,對這種情況,該機器試圖去選舉Leader時,會被告知目前伺服器的Leader資訊,對于該機器而言,僅僅需要和Leader機器建立起連接配接,并進行狀态同步即可。而在叢集中不存在Leader情況下則會相對複雜,其步驟如下
(1) 第一次投票。無論哪種導緻進行Leader選舉,叢集的所有機器都處于試圖選舉出一個Leader的狀态,即LOOKING狀态,LOOKING機器會向所有其他機器發送消息,該消息稱為投票。投票中包含了SID(伺服器的唯一辨別)和ZXID(事務ID),(SID, ZXID)形式來辨別一次投票資訊。假定Zookeeper由5台機器組成,SID分别為1、2、3、4、5,ZXID分别為9、9、9、8、8,并且此時SID為2的機器是Leader機器,某一時刻,1、2所在機器出現故障,是以叢集開始進行Leader選舉。在第一次投票時,每台機器都會将自己作為投票對象,于是SID為3、4、5的機器投票情況分别為(3, 9),(4, 8), (5, 8)。
(2) 變更投票。每台機器發出投票後,也會收到其他機器的投票,每台機器會根據一定規則來處理收到的其他機器的投票,并以此來決定是否需要變更自己的投票,這個規則也是整個Leader選舉算法的核心所在,其中術語描述如下
· vote_sid:接收到的投票中所推舉Leader伺服器的SID。
· vote_zxid:接收到的投票中所推舉Leader伺服器的ZXID。
· self_sid:目前伺服器自己的SID。
· self_zxid:目前伺服器自己的ZXID。
每次對收到的投票的處理,都是對(vote_sid, vote_zxid)和(self_sid, self_zxid)對比的過程。
規則一:如果vote_zxid大于self_zxid,就認可目前收到的投票,并再次将該投票發送出去。
規則二:如果vote_zxid小于self_zxid,那麼堅持自己的投票,不做任何變更。
規則三:如果vote_zxid等于self_zxid,那麼就對比兩者的SID,如果vote_sid大于self_sid,那麼就認可目前收到的投票,并再次将該投票發送出去。
規則四:如果vote_zxid等于self_zxid,并且vote_sid小于self_sid,那麼堅持自己的投票,不做任何變更。
結合上面規則,給出下面的叢集變更過程。
(3) 确定Leader。經過第二輪投票後,叢集中的每台機器都會再次接收到其他機器的投票,然後開始統計投票,如果一台機器收到了超過半數的相同投票,那麼這個投票對應的SID機器即為Leader。此時Server3将成為Leader。
由上面規則可知,通常那台伺服器上的資料越新(ZXID會越大),其成為Leader的可能性越大,也就越能夠保證資料的恢複。如果ZXID相同,則SID越大機會越大。
4. Leader選舉實作細節
1). 伺服器狀态
伺服器具有四種狀态,分别是LOOKING、FOLLOWING、LEADING、OBSERVING。
LOOKING:尋找Leader狀态。當伺服器處于該狀态時,它會認為目前叢集中沒有Leader,是以需要進入Leader選舉狀态。
FOLLOWING:跟随者狀态。表明目前伺服器角色是Follower。
LEADING:上司者狀态。表明目前伺服器角色是Leader。
OBSERVING:觀察者狀态。表明目前伺服器角色是Observer。
2). 投票資料結構
每個投票中包含了兩個最基本的資訊,所推舉伺服器的SID和ZXID,投票(Vote)在Zookeeper中包含字段如下
id:被推舉的Leader的SID。
zxid:被推舉的Leader事務ID。
electionEpoch:邏輯時鐘,用來判斷多個投票是否在同一輪選舉周期中,該值在服務端是一個自增序列,每次進入新一輪的投票後,都會對該值進行加1操作。
peerEpoch:被推舉的Leader的epoch。
state:目前伺服器的狀态。
三. zookeeper是如何保證事務的順序一緻性的?
zookeeper采用了全局遞增的事務Id(ZXID)來辨別,zxid記錄ZooKeeper狀态的改變,建立任意節點, 或者更新任意節點的資料, 或者删除任意節點, 都會導緻Zookeeper狀态發生改變, 進而導緻zxid的值增加。
所有的proposal(提議)都在被提出的時候加上了zxid,zxid實際上是一個64位的數字,高32位是epoch(時期; 紀元; 世; 新時代)用來辨別leader周期,如果有新的leader産生出來,epoch會自增,低32位用來遞增計數。當新産生proposal的時候,會依據資料庫的兩階段過程,首先會向其他的server發出事務執行請求,如果超過半數的機器都能執行并且能夠成功,那麼就會開始執行。
四. 四種類型的資料節點 Znode
· PERSISTENT-持久節點
除非手動删除,否則節點一直存在于Zookeeper上
· EPHEMERAL-臨時節點
臨時節點的生命周期與用戶端會話綁定,一旦用戶端會話失效(用戶端與zookeeper連接配接斷開不一定會話失效),那麼這個用戶端建立的所有臨時節點都會被移除。
· PERSISTENT_SEQUENTIAL-持久順序節點
基本特性同持久節點,隻是增加了順序屬性,節點名後邊會追加一個由父節點維護的自增整型數字。
· EPHEMERAL_SEQUENTIAL-臨時順序節點
基本特性同臨時節點,增加了順序屬性,節點名後邊會追加一個由父節點維護的自增整型數字。