Zookeeper集群啟動過程
預啟動
- 統一由QuorumPeerMain作為啟動類
-
讀取zoo.cfg配置文件
-
創建並啟動歷史文件清理器DatadirCleanupManager
-
判斷當前是集群模式還是單機模式
初始化
-
創建ServerCnxnFactory,
-
初始化ServerCnxnFactory,初始化一個線程,作為整個ServerCnxnFactory的主線程然后在初始化NIO服務器
-
創建Zookeeper數據管理器FileTxnSnapLog,
-
創建QuorumPeer實例,Quorum是集群模式下特有的對象,是Zookeeper服務器實例的托管者,從集群層面來看QuorumPeer代表了Zookeeper集群中一台服務器,在運行期間它會不斷檢查當前服務器實例運行的狀態。然后根據情況進行Leader選舉。
-
創建內存數據庫ZKDatabase
-
初始化QuorumPeer,這里把一些核心組件注冊到QuorumPeer,這些核心組件包括FileTxnSnapLog、ServerCnxnFactory和ZKDatabase,同時Zookeeper還會對QuorumPeer配置一些參數,包括服務器地址列表,選舉算法和會話超時時間等。
-
恢復本地數據庫
-
啟動ServerCnxnFactory主線程
-
Leader選舉
-
交互和數據同步(看紅色部分)
-
創建會話管理器
-
初始化Zookeeper的請求處理鏈
-
注冊JMX
在Leader選舉完成之后會有一個Leader和其他服務器(Follower和Observer 統稱Learner學習者)進行交互,大致流程如下:
-
Leader服務器啟動Follower接收器,LearnerCnxAcceptor,來接收所有非Leader服務器的連接
-
Leader與每一個Learner之間都會有一個LearnerHandler實例對應負載它們之間的消息通信和數據同步
-
Learner和Leader建立連接后,Learner向Leader注冊,就是發送自己的信息給Leader,包括當前服務器的SID和ZXID
-
Leader解析Learner發來的注冊信息,在過半向Leader注冊的服務器中找到最大的epoch,然后加1,用於確定當前集群的epoch
-
Leader發送LEADERINFO給Learner
-
Learner收到LEADERINFO,解析出epoch和ZXID然后給Leader一個反饋
-
Leader收到Learner響應之后就開始與其進行數據同步
-
啟動Leader和Learner服務器,有過半數完成數據同步就可以啟動了。
Leader選舉
選舉原則就是比計較MYID、ZXID,這里我們以3台為例,其實2台也可以完成選舉,但是通常集群規模最小是3台
服務器啟動期間的選舉
Server1 myid:1 zxid:0
Server2 myid:2 zxid:0
Server3 myid:3 zxid:0
-
每個服務器都會發出一條投票且都是投給自己,以Server1為例(1,0),把這個信息發送到集群中其他服務器上。當然它自己也會收到別人的投票信息
-
每個服務器收到其他服務器的投票,先會檢查有效性包括檢查是否是本輪投票以及是否來自LOOKING狀態的服務器發出的
-
處理投票,首先比較ZXID,值最大的為Leader,如果值一樣那么就比較myid,myid最大的為Leader,Server1會收到(1,0)(2,0)(3,0)經過比較自己的myid不是最大的,它會重新投票新的投票(3,0)並從新發到集群中去,對於Server2也一樣,對於Server3來說它不用更新投票信息它比較后自己就是最大的所有再次發出投自己的票就可以。這樣每個機器又會收到2個投票信息,Server1會收到Server2、3發來的(3,0)。
-
每次投票服務器都會進行投票統計,判斷是否有超過半數機器相同的投票信息,對於這三台服務器來說最終投票結果是(3,0),那么除了Server3之外其他都會收到2張(3,0)的投票,這樣在一個3台集群中超過半數投票是投給一個機器的,那么這個機器就是集群的Leader。
-
一旦確定了Leader那么就需要設置自己的角色以及改變自己的狀態Leader變成LEADING,而Follower就變成FOLLOWING。
服務器運行期間的選舉
當集群中的服務器數量發生變化時才會進行重新選舉,比如之前的Leader故障或者新加入一台Zookeeper服務器。
我們假設上面的Leader Server3掛了,然后重新選舉
Server1 myid:1 zxid:123
Server2 myid:2 zxid:122
Server3 myid:3 zxid: (宕機)
-
當集群感知到Leader掛了,那么所有Follower角色的服務器就轉變狀態從FOLLOWING變成LOOKING
-
每個服務器發出投票Server1會發出(1,123)到集群中,Server2會發出(2,122)到集群中,因為第一輪都是投自己。
-
集群中可用服務器收到投票
-
投票處理,這里和啟動時候使用相同的原則,Server1投票不變因為它的ZXID比Server2的大,所以它再次發一個投自己的票,Server2發現自己的ZXID小所以更新投票信息(1,123)再次發出去
-
統計投票信息,最終Server1勝出成為Leader
-
改變服務器狀態