zookeeper-選舉機制


關於zookeeper的選舉機制

Leader的初次選舉和運行中Leader宕機再次選舉;

Leader的選舉機制;

 

————————————————
借鑒原文鏈接:https://blog.csdn.net/wyqwilliam/article/details/83537139

 

為什么要選舉出Leader?

  Leader的作用:

  1、處理所有的寫請求並同步給Follower

  2、啟動時同步數據給Follewer節點 

 

1、服務器啟動時期的Leader選舉,即初次選舉:

  在集群初始化階段,當有一台服務器Server1啟動時,其單獨無法進行和完成Leader選舉,當第二台服務器Server2啟動時,

兩台機器此時可以相互通信,每台機器都試圖找到Leader,於是進入選舉過程。

  選舉過程如下:

  (1)每個Server發出一個投票,由於是初始情況,Server1和server2都會將自己作為Leader服務器來進行投票。

每台服務器會往其他服務器發送投票信息,這個投票信息包括了SID和ZXID,其中SID就是該台機器的唯一標識(myid);

ZXID是事務id,該ID是64位的,分為高32位和低32位。

  (2)由於是初次投票,此時的ZXID相同,所以比較的就是SID,SID越大,獲得的Leader的可能越大(為了嚴謹,

本文針對任何情況都只說可能,不說絕對)。

  (3)兩台服務器發出自己的投票信息后,再根據自己收到的其他服務器的投票信息決定自己的投票信息是否變更,第一台服務器SID為1,第二台服務器SID為2,所以Server2的投票變更為2,

即有兩票,由於一共三台服務器,此時Server2已經處於半數以上,所以決定出來的Leader為Server2;(半數投票)即使Server3啟動,

由於Leader已經決定出來,所以不需要在進行投票,Server3只需要與Leader建立連接並進行狀態同步即可。

 

2、Leader突然宕機,重新進行選舉

  假如此時有5台服務器,並且已經選舉出Server3作為Leader,突然Leader(Server3)宕機,那么此時其他四台服務器要進行重新選舉,

它們便會進入LOOKING狀態。

  (1)在運行期間,它們的ZXID可能不會相同,於是再新一輪的Leader選舉中,不僅僅需要比較SID,還要比較ZXID,ZXID越大,

選舉成Leader的可能越大。

  (2)在初次選舉中我們可以得出一個結論,便是SID位於中間,選舉出Leader的可能性最大。但在運行時Leader突然宕機,再次進行

選舉時,這種結論已經不適用了,有可能選舉出的Leader是Server1,也有可能是Server2,或者是Server4、Server5。

  (3)值得注意的一點是,剛剛說了ZXID越大,選舉出Leader的可能越大,前面說過ZXID分為高32位和低32位,這里要標紅:ZXID中的

低32位相比較的話,低32位越小的一方得到的Leader的可能性越大。

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選舉實現細節

  看到這已經對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:當前服務器的狀態。

  3. QuorumCnxManager:網絡I/O

    每台服務器在啟動的過程中,會啟動一個QuorumPeerManager,負責各台服務器之間的底層Leader選舉過程中的網絡通信。

  (1) 消息隊列。QuorumCnxManager內部維護了一系列的隊列,用來保存接收到的、待發送的消息以及消息的發送器,除接收隊列以外,其他隊列都按照SID分組形成隊列集合,如一個集群中除了自身還有3台機器,那么就會為這3台機器分別創建一個發送隊列,互不干擾。

    · recvQueue:消息接收隊列,用於存放那些從其他服務器接收到的消息。

    · queueSendMap:消息發送隊列,用於保存那些待發送的消息,按照SID進行分組。

    · senderWorkerMap:發送器集合,每個SenderWorker消息發送器,都對應一台遠程Zookeeper服務器,負責消息的發送,也按照SID進行分組。

    · lastMessageSent:最近發送過的消息,為每個SID保留最近發送過的一個消息。

  (2) 建立連接。為了能夠相互投票,Zookeeper集群中的所有機器都需要兩兩建立起網絡連接。QuorumCnxManager在啟動時會創建一個ServerSocket來監聽Leader選舉的通信端口(默認為3888)。開啟監聽后,Zookeeper能夠不斷地接收到來自其他服務器的創建連接請求,在接收到其他服務器的TCP連接請求時,會進行處理。為了避免兩台機器之間重復地創建TCP連接,Zookeeper只允許SID大的服務器主動和其他機器建立連接,否則斷開連接。在接收到創建連接請求后,服務器通過對比自己和遠程服務器的SID值來判斷是否接收連接請求,如果當前服務器發現自己的SID更大,那么會斷開當前連接,然后自己主動和遠程服務器建立連接。一旦連接建立,就會根據遠程服務器的SID來創建相應的消息發送器SendWorker和消息接收器RecvWorker,並啟動。

  (3) 消息接收與發送。消息接收:由消息接收器RecvWorker負責,由於Zookeeper為每個遠程服務器都分配一個單獨的RecvWorker,因此,每個RecvWorker只需要不斷地從這個TCP連接中讀取消息,並將其保存到recvQueue隊列中。消息發送:由於Zookeeper為每個遠程服務器都分配一個單獨的SendWorker,因此,每個SendWorker只需要不斷地從對應的消息發送隊列中獲取出一個消息發送即可,同時將這個消息放入lastMessageSent中。在SendWorker中,一旦Zookeeper發現針對當前服務器的消息發送隊列為空,那么此時需要從lastMessageSent中取出一個最近發送過的消息來進行再次發送,這是為了解決接收方在消息接收前或者接收到消息后服務器掛了,導致消息尚未被正確處理。同時,Zookeeper能夠保證接收方在處理消息時,會對重復消息進行正確的處理。

  4. FastLeaderElection:選舉算法核心

    · 外部投票:特指其他服務器發來的投票。

    · 內部投票:服務器自身當前的投票。

    · 選舉輪次:Zookeeper服務器Leader選舉的輪次,即logicalclock。

    · PK:對內部投票和外部投票進行對比來確定是否需要變更內部投票。

  (1) 選票管理

    · sendqueue:選票發送隊列,用於保存待發送的選票。

    · recvqueue:選票接收隊列,用於保存接收到的外部投票。

    · WorkerReceiver:選票接收器。其會不斷地從QuorumCnxManager中獲取其他服務器發來的選舉消息,並將其轉換成一個選票,然后保存到recvqueue中,在選票接收過程中,如果發現該外部選票的選舉輪次小於當前服務器的,那么忽略該外部投票,同時立即發送自己的內部投票。

    · WorkerSender:選票發送器,不斷地從sendqueue中獲取待發送的選票,並將其傳遞到底層QuorumCnxManager中。

  (2) 算法核心

    上圖展示了FastLeaderElection模塊是如何與底層網絡I/O進行交互的。Leader選舉的基本流程如下:

  1. 自增選舉輪次。Zookeeper規定所有有效的投票都必須在同一輪次中,在開始新一輪投票時,會首先對logicalclock進行自增操作。

  2. 初始化選票。在開始進行新一輪投票之前,每個服務器都會初始化自身的選票,並且在初始化階段,每台服務器都會將自己推舉為Leader。

  3. 發送初始化選票。完成選票的初始化后,服務器就會發起第一次投票。Zookeeper會將剛剛初始化好的選票放入sendqueue中,由發送器WorkerSender負責發送出去。

  4. 接收外部投票。每台服務器會不斷地從recvqueue隊列中獲取外部選票。如果服務器發現無法獲取到任何外部投票,那么就會立即確認自己是否和集群中其他服務器保持着有效的連接,如果沒有連接,則馬上建立連接,如果已經建立了連接,則再次發送自己當前的內部投票。

  5. 判斷選舉輪次。在發送完初始化選票之后,接着開始處理外部投票。在處理外部投票時,會根據選舉輪次來進行不同的處理。

    · 外部投票的選舉輪次大於內部投票。若服務器自身的選舉輪次落后於該外部投票對應服務器的選舉輪次,那么就會立即更新自己的選舉輪次(logicalclock),並且清空所有已經收到的投票,然后使用初始化的投票來進行PK以確定是否變更內部投票。最終再將內部投票發送出去。

    · 外部投票的選舉輪次小於內部投票。若服務器接收的外選票的選舉輪次落后於自身的選舉輪次,那么Zookeeper就會直接忽略該外部投票,不做任何處理,並返回步驟4。

    · 外部投票的選舉輪次等於內部投票。此時可以開始進行選票PK。

  6. 選票PK。在進行選票PK時,符合任意一個條件就需要變更投票。

    · 若外部投票中推舉的Leader服務器的選舉輪次大於內部投票,那么需要變更投票。

    · 若選舉輪次一致,那么就對比兩者的ZXID,若外部投票的ZXID大,那么需要變更投票。

    · 若兩者的ZXID一致,那么就對比兩者的SID,若外部投票的SID大,那么就需要變更投票。

  7. 變更投票。經過PK后,若確定了外部投票優於內部投票,那么就變更投票,即使用外部投票的選票信息來覆蓋內部投票,變更完成后,再次將這個變更后的內部投票發送出去。

  8. 選票歸檔。無論是否變更了投票,都會將剛剛收到的那份外部投票放入選票集合recvset中進行歸檔。recvset用於記錄當前服務器在本輪次的Leader選舉中收到的所有外部投票(按照服務隊的SID區別,如{(1, vote1), (2, vote2)...})。

  9. 統計投票。完成選票歸檔后,就可以開始統計投票,統計投票是為了統計集群中是否已經有過半的服務器認可了當前的內部投票,如果確定已經有過半服務器認可了該投票,則終止投票。否則返回步驟4。

  10. 更新服務器狀態。若已經確定可以終止投票,那么就開始更新服務器狀態,服務器首選判斷當前被過半服務器認可的投票所對應的Leader服務器是否是自己,若是自己,則將自己的服務器狀態更新為LEADING,若不是,則根據具體情況來確定自己是FOLLOWING或是OBSERVING。

  以上10個步驟就是FastLeaderElection的核心,其中步驟4-9會經過幾輪循環,直到有Leader選舉產生。

 


免責聲明!

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



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