Zookeeper源碼閱讀(十五) Zookeeper集羣之server啓動

前言

最近又開啓了一個新項目,時間比較緊,博客寫的速度也比較慢,可是仍是不能放鬆要求~但願最近週末能抽點時間把上週漏掉的博客補上~java

在前一篇大體描述了單機server的啓動過程後,從這一篇開始咱們將開始集羣server的一些機制的一些瞭解,主要還有servr的啓動,處理鏈,選舉等等大的模塊須要完善。算法

流程

其實從大體的流程上來講,單機server和集羣server的處理是基本一致的,都是會從主函數啓動而後去初始化一些zookeeper運行必須的一些功能類,而最大的不一樣點也就在於集羣server是分佈式的,多了一個選舉的過程,這個選舉的過程本篇不會深刻去講,應該會分爲兩篇,一篇講Zookeeper選舉依賴的ZAB算法,另外一篇主要說下具體的流程。數據庫

首先經過流程圖看下集羣server的啓動過程:分佈式

從圖中也能夠看到,確實和上一篇所說的單機server的啓動流程大體一致。ide

總的來講,和單機server的啓動過程相比,除了預啓動和初始化兩個狀態以外,還有一個leader選舉的過程。函數

預啓動

  1. 與單機server啓動過程同樣,集羣server啓動一樣以QuorumPeerMain類做爲啓動類;ui

  2. 解析zoo.cfg;this

  3. 建立並啓動歷史文件清理器DatadirCleanupManager;spa

  4. 判斷啓動模式。線程

    if (args.length == 1 && config.servers.size() > 0) {
        runFromConfig(config);
    }

    能夠看到,在集羣模式下(zoo.cfg中配置了多個server),zk會直接開始以集羣模式啓動server。這部分的啓動順序和單機版的是基本一致的,它們都是共用的同一份代碼。

初始化

在預啓動以後即是初始化的過程。

public void runFromConfig(QuorumPeerConfig config) throws IOException {
  try {
      ManagedUtil.registerLog4jMBeans();//註冊log的bean
  } catch (JMException e) {
      LOG.warn("Unable to register log4j JMX control", e);
  }

  LOG.info("Starting quorum peer");
  try {
      ServerCnxnFactory cnxnFactory = ServerCnxnFactory.createFactory();//建立ServerCnxnFactory
      cnxnFactory.configure(config.getClientPortAddress(),//初始化ServerCnxnFactory
                            config.getMaxClientCnxns());

      //建立並初始化QuorumPeer
      quorumPeer = getQuorumPeer();

      //初始化的數據基本都是從zoo.cfg中讀到的值,方法名也叫runFromConfig
      quorumPeer.setQuorumPeers(config.getServers());
      quorumPeer.setTxnFactory(new FileTxnSnapLog(//建立數據管理器FileTxnSnapLog
              new File(config.getDataLogDir()),
              new File(config.getDataDir())));
      quorumPeer.setElectionType(config.getElectionAlg());
      quorumPeer.setMyid(config.getServerId());
      quorumPeer.setTickTime(config.getTickTime());
      quorumPeer.setInitLimit(config.getInitLimit());
      quorumPeer.setSyncLimit(config.getSyncLimit());
      quorumPeer.setQuorumListenOnAllIPs(config.getQuorumListenOnAllIPs());
      quorumPeer.setCnxnFactory(cnxnFactory);
      quorumPeer.setQuorumVerifier(config.getQuorumVerifier());
      quorumPeer.setClientPortAddress(config.getClientPortAddress());
      quorumPeer.setMinSessionTimeout(config.getMinSessionTimeout());
      quorumPeer.setMaxSessionTimeout(config.getMaxSessionTimeout());
      quorumPeer.setZKDatabase(new ZKDatabase(quorumPeer.getTxnFactory()));
      quorumPeer.setLearnerType(config.getPeerType());
      quorumPeer.setSyncEnabled(config.getSyncEnabled());

      // sets quorum sasl authentication configurations
      quorumPeer.setQuorumSaslEnabled(config.quorumEnableSasl);
      if(quorumPeer.isQuorumSaslAuthEnabled()){
          quorumPeer.setQuorumServerSaslRequired(config.quorumServerRequireSasl);
          quorumPeer.setQuorumLearnerSaslRequired(config.quorumLearnerRequireSasl);
          quorumPeer.setQuorumServicePrincipal(config.quorumServicePrincipal);
          quorumPeer.setQuorumServerLoginContext(config.quorumServerLoginContext);
          quorumPeer.setQuorumLearnerLoginContext(config.quorumLearnerLoginContext);
      }

      quorumPeer.setQuorumCnxnThreadsSize(config.quorumCnxnThreadsSize);
      quorumPeer.initialize();

      quorumPeer.start();
      quorumPeer.join();
  } catch (InterruptedException e) {
      // warn, but generally this is ok
      LOG.warn("Quorum Peer interrupted", e);
  }
}

經過上面的代碼及註釋能夠看出,初始化過程分爲下面幾步:

  1. 建立和初始化ServerCnxnFactory;
  2. 建立QuorumPeer實例,並初始化。
    1. 建立數據管理器FileTxnSnapLog;
    2. 建立內存數據庫ZKDatabase;
  3. 恢復本地數據;
  4. 啓動ServerCnxnFactory線程。

3,4兩步都是在quorumPeer.start();中完成的,特別要注意的是,QuorumPeer重寫了thread類的start方法,因此這裏調用了start方法並非直接去調用QuorumPeer的run方法,而真正調用QuorumPeer的run方法是在QuorumPeer的start方法中super.start()這一步。

@Override
public synchronized void start() {
    loadDataBase();//恢復本地數據
    cnxnFactory.start();//啓動ServerCnxnFactory線程
    startLeaderElection();//啓動leader選舉
    super.start();//啓動QuorumPeer線程,並在
}

這裏能夠看到,在start的過程當中,會有一步是作leader的選舉的,而這也是集羣和單機server啓動時最大的區別,這一步將在下篇博客中專門講一下。

而至於super.start(),這部分主要乾了兩個是:

  1. JMX服務註冊;
  2. 檢查server狀態,並在適當狀態進行leader選舉。

這兩部在下篇也會詳細說。

思考

單機和集羣server啓動中,除了集羣server啓動多了一個leader選舉過程外,還有個區別是單機server會讀兩遍zoo.cfg,其實爲何不在ZookeeperMain裏「重載」main方法(寫個流程差很少的方法),以QuorumPeerConfig做爲參數,這樣就不用讀第二遍了。不過估計是由於讀配置工做量比較小,因此沒有作這個事。

參考

從paxos到zk

相關文章
相關標籤/搜索