天天看點

Zookeeper 源碼 叢集啟動 與 啟動時 leader 選舉準備選舉架構leader 選舉

博文目錄

文章目錄

  • 準備
    • 為什麼要看源碼
    • 看源碼方法
    • 下載下傳源碼
    • 找到主類
    • 配置參數
    • 啟動服務
    • 用戶端連接配接
  • 選舉架構
  • leader 選舉
    • 叢集選舉原理
      • 3節點叢集, 先啟動兩台節點

準備

為什麼要看源碼

1、提升技術功底:學習源碼裡的優秀設計思想,比如一些疑難問題的解決思路,還有一些優秀的設計模式,整體提升自己的技術功底

2、深度掌握技術架構:源碼看多了,對于一個新技術或架構的掌握速度會有大幅提升,看下架構demo大緻就能知道底層的實作,技術架構更新再快也不怕

3、快速定位線上問題:遇到線上問題,特别是架構源碼裡的問題(比如bug),能夠快速定位,這就是相比其他沒看過源碼的人的優勢

4、對面試大有裨益:面試一線網際網路公司對于架構技術一般都會問到源碼級别的實作

5、知其然知其是以然:對技術有追求的人必做之事,使用了一個好的架構,很想知道底層是如何實作的

6、擁抱開源社群:參與到開源項目的研發,結識更多大牛,積累更多優質人脈

看源碼方法

1、先使用:先看官方文檔快速掌握架構的基本使用

2、抓主線:找一個demo入手,順藤摸瓜快速靜态看一遍架構的主線源碼,畫出源碼主流程圖,切勿一開始就陷入源碼的細枝末節,否則會把自己繞暈,憑經驗猜

3、畫圖做筆記:總結架構的一些核心功能點,從這些功能點入手深入到源碼的細節,邊看源碼邊畫源碼走向圖,并對關鍵源碼的了解做筆記,把源碼裡的閃光點都記錄下來,後續借鑒到工作項目中,了解能力強的可以直接看靜态源碼,也可以邊看源碼邊debug源碼執行過程,觀察一些關鍵變量的值

4、整合總結:所有功能點的源碼都分析完後,回到主流程圖再梳理一遍,争取把自己畫的所有圖都在腦袋裡做一個整合

下載下傳源碼

Zookeeper

Zookeeper 3.5.8

Zookeeper 源碼 叢集啟動 與 啟動時 leader 選舉準備選舉架構leader 選舉

源碼導入idea後,org.apache.zookeeper.Version類會報錯,需要建一個輔助接口 org.apache.zookeeper.version.Info (.gitignore裡忽略了)

package org.apache.zookeeper.version;

public interface Info {
	int MAJOR = 1;
	int MINOR = 0;
	int MICRO = 0;
	String QUALIFIER = null;
	int REVISION = -1;
	String REVISION_HASH = "1";
	String BUILD_DATE = "2020-11-23";
}
           

找到主類

開源項目找入口類一般都是從啟動腳本去找,可以從bin目錄下的zkServer.sh或zkServer.cmd裡找到啟動主類 ZOOMAIN 即 org.apache.zookeeper.server.quorum.QuorumPeerMain

配置參數

在應用目錄下建立 /data 目錄, 并建立 /2181, /2182, /2183 3個子目錄, 在其内建立 myid 檔案, 分别填寫 1,2,3

複制 zoo_sample.cfg 為 zoo.2181.cfg, 修改 dataDir 為 /data/2181 目錄的絕對路徑, 注意路徑分割符需要使用 / 或者 \

直接運作主類就, 在 Configuration 裡面新增一個配置

  • 修改該配置, 命名為 QuorumPeerMain 2181, 在 Program arguments 中把 zoo.2181.cfg 的絕對路徑配置進去
  • zookeeper預設使用NIOServerCnxnFactory, 但是推薦使用NettyServerCnxnFactory, 可以配置如下VM參數來啟用

    -Dzookeeper.serverCnxnFactory=org.apache.zookeeper.server.NettyServerCnxnFactory

啟動之前需要先将zookeeper-server項目裡pom.xml檔案裡依賴的包(除了jline)的scope為provided這一行全部注釋掉

将conf檔案夾裡的log4j.properties檔案複制一份到zookeeper-server項目的 \target\classes 目錄下(沒有的話先編譯下工程),這樣項目啟動時才會列印日志

Zookeeper 源碼 叢集啟動 與 啟動時 leader 選舉準備選舉架構leader 選舉

啟動服務

啟動第一台節點的時候, 會報錯, 是因為首次啟動, 也會選舉leader, 因為其他服務還沒啟動, 是以第一台連接配接不到, 是以報錯, 正常現象

還有一個報錯是 zookeeper admin 啟動了一個服務, 用于檢視叢集狀态等配置, 在端口8080, 第一台服務啟動後, 其他再次使用8080端口就會報錯, 正常現象, 無需理會

理論上, 兩台服務啟動後, 已經滿足大多數(配了3個節點, 1半是1, 大多數是一半加1即2)的條件, 選舉将會成功

而且檢視日志, 可觀察到, 第一台啟動的機子是follower, 第二台啟動的機子是leader, 第三台啟動的機子是follower

用戶端連接配接

或者使用 用戶端 org.apache.zookeeper.ZooKeeperMain, 注意配置參數 -server 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183

Zookeeper 源碼 叢集啟動 與 啟動時 leader 選舉準備選舉架構leader 選舉

然後在輸出的地方直接使用 ls / 等指令即可正常執行

選舉架構

Zookeeper 源碼 叢集啟動 與 啟動時 leader 選舉準備選舉架構leader 選舉

leader 選舉

選舉周期: 每一個選舉周期内會選出來一個leader, 不是發一次選票周期就加1

叢集節點數: 配置檔案中 server.id 配置的條數

叢集選舉節點數: 配置檔案中 server.id 配置中, participant 配置(非observer配置)的條數

完成選舉所需的最小節點數:

Leader節點被選出的判斷公式: 某節點獲得的選票數 >= 叢集選舉節點數 / 2 + 1, 注意除法截斷小數

叢集選舉原理

參與叢集選舉的機器是在配置檔案中配置的(observer節點不參與選舉, 也不計入投票機器的總數半數中). 整個叢集中有過半的機器啟動成功即可完成Leader選舉, 每一個節點會給所有參與選舉的節點發送選票(包括它自己), 是以每一個節點都會拿到每一輪投票期内所有投票節點的所有選票, 選舉可能在多輪投票後才會成功, 成功的條件就是某節點獲得的選票超過半數. 每一個節點通過每一輪的所有投票自行判斷自己該是什麼狀态(looking,leading,following,observing), 各自的判斷都不會沖突

return ((newEpoch > curEpoch) ||
        ((newEpoch == curEpoch) &&
        ((newZxid > curZxid) || ((newZxid == curZxid) && (newId > curId)))));
           

每一台節點内部維護着下次發送選票的資訊, 包括 serverId:下次投票時選票的節點id, zxid:下次投票時選票的最大事務id, epoch:下次投票時的選舉周期, 啟動時會初始化serverId=myid, zxid=myMaxZxid, epoch=?, 當接收到的選票比自己維護的選票更新時(即上述判斷為true), 把自己維護的選票資訊更新一下

第一輪投票(啟動時投票), 每台節點一定會提名自己成為leader, 接收到其他節點的投票後, 優先推舉maxZxid最大的節點(資料最多)成為leader, 在首次啟動的時候, 因為各節點都沒有資料, 是以maxZxid都是0, 這時候會推舉myid最大的節點成為leader

3節點叢集, 先啟動兩台節點

先啟動myid為1的機器, 再啟動myid為2的機器, 兩台機器成功連接配接并開始選舉

第一輪投票: 1發送(1,0)給1和2, 2發送(2,0)給1和2, 這時1内投給1的票數是1, 投給2的票數是1, 2内投給1的票數是1, 投給2的票數是1, 兩個節點的票數都沒有超過叢集半數(3節點,大多數指的是2), 需要第二輪投票. 因為是首輪投票, zxid都是0, 1發現在maxZxid一緻的情況下, 2的id比較大, 是以下一輪計劃投(2,0), 2也發現自己的id比較大, 下一輪也投(2,0)

第二輪投票: 1發送(2,0)給1和2, 2發送(2,0)給1和2, 這時1内投給1的票數是0, 投給2的票數是2, 2内投給1的票數是0, 投給2的票數是2, 2的選票數達到了叢集半數, 2被選為叢集leader, 1則自動成為follower

這時啟動myid為3的機器, 仍然是looking狀态, 任然會發送選票, 隻不過epoch是0, 此時1和2已經不是LOOKING狀态了, 都對比發現發現叢集已有leader, 是以3自動成為follower