Apache ZooKeeper -从初始化到对外提供服务的过程解析( 集群模式 )
文章目錄
- 流程圖
- Pre
- 什么是集群模式?
- ZooKeeper 集群模式的特點
- 底層實現原理
- 程序啟動
- QuorumPeer 類
- Leader 服務器啟動過程
- Follow 服務器啟動過程
- 小結
流程圖
Pre
Apache ZooKeeper -從初始化到對外提供服務的過程解析( 單機模式 )
我們知道了 ZooKeeper 在單機模式下從啟動運行到對外提供服務的整個過程。在日常工作中,無論是出于性能上的優勢還是可靠性的考慮,單機模式都無法滿足要求。因此,ZooKeeper 也采用集群的方式運行。我們就來學習一下 ZooKeeper 集群模式下,啟動過程的底層實現。
什么是集群模式?
為了解決單機模式下性能的瓶頸問題,以及出于對系統可靠性的高要求,集群模式的系統架構方式被業界普遍采用。
集群模式可以簡單理解為將單機系統復制成幾份,部署在不同主機或網絡節點上,最終構成了一個由多臺計算機組成的系統“集群”。而組成集群中的每個服務器叫作集群中的網絡節點。
那問題來了 我們應該如何使用集群?當客戶端發送一個請求到集群服務器的時候,究竟是哪個機器為我們提供服務呢?
為了解決這個問題,先介紹一個概念名詞“調度者”。調度者的工作職責就是在集群收到客戶端請求后,根據當前集群中機器的使用情況,決定將此次客戶端請求交給哪一臺服務器或網絡節點進行處理,例如我們都很熟悉的負載均衡服務器就是一種調度者的實現方式。
ZooKeeper 集群模式的特點
通過上面的介紹,我們知道了集群是由網絡中不同機器組成的一個系統,集群工作是通過集群中調度者服務器來協同工作的。
那么現在我們來看一下 ZooKeeper 中的集群模式,在 ZooKeeper 集群模式中,相比上面說到的集群架構方式,在 ZooKeeper 集群中將服務器分成 Leader 、Follow 、Observer 三種角色服務器,在集群運行期間這三種服務器所負責的工作各不相同:
- Leader 角色服務器負責管理集群中其他的服務器,是集群中工作的分配和調度者。
- Follow 服務器的主要工作是選舉出 Leader 服務器,在發生 Leader 服務器選舉的時候,系統會從 Follow 服務器之間根據多數投票原則,選舉出一個 Follow 服務器作為新的 Leader 服務器。
- Observer 服務器則主要負責處理來自客戶端的獲取數據等請求,并不參與 Leader 服務器的選舉操作,也不會作為候選者被選舉為 Leader 服務器。
接下來我們看看在 ZooKeeper 中集群是如何架構和實現的。
底層實現原理
到目前為止我們對 ZooKeeper 中集群相關的知識有了大體的了解,接下來我們就深入到 ZooKeeper 的底層,看看在服務端,集群模式是如何啟動到對外提供服務的。
在上一篇博文中已經對 ZooKeeper 單機版服務的啟動過程做了詳細的介紹。而集群中的啟動過程和單機版的啟動過程有很多地方是一樣的。所以本次我們只對 ZooKeeper 集群中的特有實現方式做重點介紹。
程序啟動
首先,在 ZooKeeper 服務啟動后,系統會調用入口 QuorumPeerMain 類中的 main 函數。在 main 函數中的 initializeAndRun 方法中根據 zoo.cfg 配置文件,判斷服務啟動方式是集群模式還是單機模式。
在函數中首先根據 arg 參數和 config.isDistributed() 來判斷,如果配置參數中配置了相關的配置項,并且已經指定了集群模式運行,那么在服務啟動的時候就會跳轉到 runFromConfig 函數完成之后的集群模式的初始化工作。
protected void initializeAndRun(String[] args){...if (args.length == 1 && config.isDistributed()) {runFromConfig(config);} else {ZooKeeperServerMain.main(args);} }QuorumPeer 類
在 ZooKeeper 服務的集群模式啟動過程中,一個最主要的核心類是 QuorumPeer 類。我們可以將每個 QuorumPeer 類的實例看作集群中的一臺服務器。在 ZooKeeper 集群模式的運行中,一個 QuorumPeer 類的實例通常具有 3 種狀態,分別是參與 Leader 節點的選舉、作為 Follow 節點同步 Leader 節點的數據,以及作為 Leader 節點管理集群中的 Follow 節點。
介紹完 QuorumPeer 類后,下面我們看一下在 ZooKeeper 服務的啟動過程中,針對 QuorumPeer 類都做了哪些工作。如下面的代碼所示,在一個 ZooKeeper 服務的啟動過程中,首先調用 runFromConfig 函數將服務運行過程中需要的核心工具類注冊到 QuorumPeer 實例中去。
這些核心工具就是我們在單機版服務的啟動中介紹的諸如 FileTxnSnapLog 數據持久化類、ServerCnxnFactory 類 NIO 工廠方法等。這之后還需要配置服務器地址列表、Leader 選舉算法、會話超時時間等參數到 QuorumPeer 實例中。
public void runFromConfig(QuorumPeerConfig config){ServerCnxnFactory cnxnFactory = null;ServerCnxnFactory secureCnxnFactory = null;...quorumPeer = getQuorumPeer()quorumPeer.setElectionType(config.getElectionAlg());quorumPeer.setCnxnFactory(cnxnFactory);... }與開篇中提到的一般構建集群的方式不同,ZooKeeper 將集群中的機器分為 Leader 、 Follow 、Obervser 三種角色,每種角色服務器在集群中起到的作用都各不相同。
比如 Leader 角色服務器主要負責處理客戶端發送的數據變更等事務性請求操作,并管理協調集群中的 Follow 角色服務器。
而 Follow 服務器則主要處理客戶端的獲取數據等非事務性請求操作。
Observer 角色服務器的功能和 Follow 服務器相似,唯一的不同就是不參與 Leader 頭節點服務器的選舉工作。
在 ZooKeeper 中的這三種角色服務器,在服務啟動過程中也有各自的不同,下面我們就以 Leader 角色服務器的啟動和 Follow 服務器服務的啟動過程來看一下各自的底層實現原理。
Leader 服務器啟動過程
在 ZooKeeper 集群中,Leader 服務器負責管理集群中其他角色服務器,以及處理客戶端的數據變更請求。因此,在整個 ZooKeeper 服務器中,Leader 服務器非常重要。所以在整個 ZooKeeper 集群啟動過程中,首先要先選舉出集群中的 Leader 服務器。
在 ZooKeeper 集群選舉 Leader 節點的過程中,首先會根據服務器自身的服務器 ID(SID)、最新的 ZXID、和當前的服務器 epoch (currentEpoch)這三個參數來生成一個選舉標準。之后,ZooKeeper 服務會根據 zoo.cfg 配置文件中的參數,選擇參數文件中規定的 Leader 選舉算法,進行 Leader 頭節點的選舉操作。
而在 ZooKeeper 中提供了三種 Leader 選舉算法,分別是
- LeaderElection
- AuthFastLeaderElection
- FastLeaderElection
在我們日常開發過程中,可以通過在 zoo.cfg 配置文件中使用 electionAlg 參數屬性來制定具體要使用的算法類型。
在 ZooKeeper 集群模式下服務啟動后。首先會創建用來選舉 Leader 節點的工具類 QuorumCnxManager 。
下面這段代碼給出了 QuorumCnxManager 在創建實例的時候首先要實例化 Listener 對象用于監聽 Leader 選舉端口。
package org.apache.zookeeper.server.quorum; public class QuorumCnxManager { ...public QuorumCnxManager(QuorumPeer self) {String cnxToValue = System.getProperty("zookeeper.cnxTimeout")listener = new Listener();listener.setName("QuorumPeerListener");}... }而在 ZooKeeper 中,Leader 選舉的大概過程,總體說來就是在集群中的所有機器中直接進行一次選舉投票,選舉出一個最適合的機器作為 Leader 節點。
而具體的評價標準就是我們上面提到的三種選舉算法。而從 3.4.0 版本開始,ZooKeeper 只支持 FastLeaderElection 這一種選舉算法。同時沒有被選舉為 Leader 節點的機器則作為 Follow 或 Observer 節點機器存在。
Follow 服務器啟動過程
現在,我們已經選舉出 ZooKeeper 集群模式下的 Leader 節點機器了。我們再看一下 Follow 節點機器在 ZooKeeper 集群模式下服務器的啟動過程。
在服務器的啟動過程中,Follow 機器的主要工作就是和 Leader 節點進行數據同步和交互。當 Leader 機器啟動成功后,Follow 節點的機器會收到來自 Leader 節點的啟動通知。而該通知則是通過 LearnerCnxAcceptor 類來實現的。該類就相當于一個接收器。專門用來接收來自集群中 Leader 節點的通知信息。
下面這段代碼中 LearnerCnxAcceptor 類首先初始化要監聽的 Leader 服務器地址和設置收到監聽的處理執行方法等操作 。
class LearnerCnxAcceptor extends ZooKeeperCriticalThread {private volatile boolean stop = false;public LearnerCnxAcceptor() {super("LearnerCnxAcceptor-" + ss.getLocalSocketAddress(), zk.getZooKeeperServerListener());}}在接收到來自 Leader 服務器的通知后,Follow 服務器會創建一個 LearnerHandler 類的實例,用來處理與 Leader 服務器的數據同步等操作。
package org.apache.zookeeper.server.quorum; public class LearnerHandler extends ZooKeeperThread {protected final Socket sock;final Leader leader;... }在完成數據同步后,一個 ZooKeeper 服務的集群模式下啟動的關鍵步驟就完成了,整個服務就處于運行狀態,可以對外提供服務了。
小結
主要學習了 ZooKeeper 集群模式的啟動過程和底層實現。與一般的集群架構不同,ZooKeeper 集群模式把其中的機器分成 Leader 、Follow 、Obsever 三種角色。
當作為 Leader 節點的機器失效時,系統會根據配置文件中的選舉算法產生新的節點。這種方式避免了一般集群模式中產生的單點失效等問題。
那在我們日常使用 ZooKeeper 集群服務器的時候,集群中的機器個數應該如何選擇?
答案是最好使用奇數原則,最小的集群配置應該是三個服務器或者節點。而如果采用偶數,在 Leader 節點選舉投票的過程中就不滿足大多數原則,這時就產生“腦裂”這個問題。
總結
以上是生活随笔為你收集整理的Apache ZooKeeper -从初始化到对外提供服务的过程解析( 集群模式 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Apache ZooKeeper - Z
- 下一篇: Keepalived - Keepal