1. 程式人生 > >Zookeeper選舉演算法原理

Zookeeper選舉演算法原理

Zookeeper選舉演算法原理

Leader選舉

Leader選舉是保證分散式資料一致性的關鍵所在。當Zookeeper叢集中的一臺伺服器出現以下兩種情況之一時,需要進入Leader選舉。

 (1) 伺服器初始化啟動。(叢集的每個節點都沒有資料 → 以SID的大小為準)

 (2) 伺服器執行期間無法和Leader保持連線。(叢集的每個節點都有資料 ,或者Leader 宕機→ 以ZXID 和 SID 的最大值為準)

 

1. 伺服器啟動時期的Leader選舉

  若進行Leader選舉,則至少需要2臺機器,兩臺的高可用性會差一些,如果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) 改變伺服器的狀態。與啟動時過程相同。


2.2 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越大機會越大。

2.3 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:當前伺服器的狀態。