zookeeper源码解析-zk集群启动

1.引入

在前面我们已经介绍了zk的单机启动,其过程也是比较简单,主要是启动zk服务,zk admin服务,创建管理快照和事务日志的FileTxnSnapLog对象等。现在我们来说一下zk集群启动过程,这也是zk生产环境启动服务的方式。

2.从QuorumPeerMain.main说起

单机启动和集群启动的都是从QuorumPeerMain.main这个方法开始,只是由于配置文件不同,最终会运行在不同的环境中,单机启动不用设置和多节点相关的配置,比如zoo.cfg配置文件示例:

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper
clientPort=2181

如果要启动集群服务,可以使用如下配置:

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper
clientPort=2181
# myid=1和2的选举和内部通讯地址
server.1=localhost:2888:3888
server.2=localhost:2889:3889

可以看出,集群配置明显需要指定多个节点之间的配置,所有在执行QuorumPeerMain.main方法时,我们需要传入类似下面的配置参数。

根据前面单机启动,我们知道最终会根据参数情况,执行不同的zk服务(启动前,配置解析和事务日志与快照清理等操作跳过)

   // 当配置了多节点信息,config.isDistributed()=true
   if (args.length == 1 && config.isDistributed()) {
            // 分布式模式
            runFromConfig(config);
    } else {
            // 单机模式
            ZooKeeperServerMain.main(args);
        }

如果以集群方式运行,最终会调用QuorumPeerMain.runFromConfig方法。这个方法执行过程如下:

  1. 注册jmx
  2. 创建服务端/安全协议的服务端对象,用于接口zk客户端的请求
  3. 创建quorumPeer对象(quorumPeer看做一个zk节点),设置事务快照操作对象,选举方式,认证服务等属性
  4. 启动节点服务(重点)
 public void runFromConfig(QuorumPeerConfig config)
            throws IOException, AdminServerException
    {
      try {
          // 注册jmx
          ManagedUtil.registerLog4jMBeans();
      } catch (JMException e) {
          LOG.warn("Unable to register log4j JMX control", e);
      }

      LOG.info("Starting quorum peer");
      try {
          ServerCnxnFactory cnxnFactory = null;
          ServerCnxnFactory secureCnxnFactory = null;

          if (config.getClientPortAddress() != null) {
              cnxnFactory = ServerCnxnFactory.createFactory();
              // 配置客户端连接端口
              cnxnFactory.configure(config.getClientPortAddress(),
                      config.getMaxClientCnxns(),
                      false);
          }

          if (config.getSecureClientPortAddress() != null) {
              secureCnxnFactory = ServerCnxnFactory.createFactory();
              // 配置安全连接端口
              secureCnxnFactory.configure(config.getSecureClientPortAddress(),
                      config.getMaxClientCnxns(),
                      true);
          }
          // ------------初始化当前zk服务节点的配置----------------
          quorumPeer = getQuorumPeer();
          // 设置数据和快照操作
          quorumPeer.setTxnFactory(new FileTxnSnapLog(
                      config.getDataLogDir(),
                      config.getDataDir()));
          quorumPeer.enableLocalSessions(config.areLocalSessionsEnabled());
          quorumPeer.enableLocalSessionsUpgrading(
              config.isLocalSessionsUpgradingEnabled());
          //quorumPeer.setQuorumPeers(config.getAllMembers());
          // 选举类型
          quorumPeer.setElectionType(config.getElectionAlg());
          // server Id
          quorumPeer.setMyid(config.getServerId());
          quorumPeer.setTickTime(config.getTickTime());
          quorumPeer.setMinSessionTimeout(config.getMinSessionTimeout());
          quorumPeer.setMaxSessionTimeout(config.getMaxSessionTimeout());
          quorumPeer.setInitLimit(config.getInitLimit());
          quorumPeer.setSyncLimit(config.getSyncLimit());
          quorumPeer.setConfigFileName(config.getConfigFilename());

          // 设置zk的节点数据库
          quorumPeer.setZKDatabase(new ZKDatabase(quorumPeer.getTxnFactory()));
          quorumPeer.setQuorumVerifier(config.getQuorumVerifier(), false);
          if (config.getLastSeenQuorumVerifier()!=null) {
              quorumPeer.setLastSeenQuorumVerifier(config.getLastSeenQuorumVerifier(), false);
          }
          // 初始化zk数据库
          quorumPeer.initConfigInZKDatabase();
          quorumPeer.setCnxnFactory(cnxnFactory);
          quorumPeer.setSecureCnxnFactory(secureCnxnFactory);
          quorumPeer.setSslQuorum(config.isSslQuorum());
          quorumPeer.setUsePortUnification(config.shouldUsePortUnification());
          quorumPeer.setLearnerType(config.getPeerType());
          quorumPeer.setSyncEnabled(config.getSyncEnabled());
          quorumPeer.setQuorumListenOnAllIPs(config.getQuorumListenOnAllIPs());
          if (config.sslQuorumReloadCertFiles) {
              quorumPeer.getX509Util().enableCertFileReloading();
          }

          // 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);
          // -------------初始化当前zk服务节点的配置---------------

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

quorumPeer.start是实现的重点,所以看看这个方法是如何实现的:

  1. 加载zk数据库,由于zk服务运行过程中会将数据保存到快照和事务日志文件中,所以在启动时需要将这些磁盘上的数据加载到zk内存数据库中
  2. 启动服务端(含安全协议服务端)
  3. 启动zk admin服务(即每一个zk服务节点上都有一个zk admin服务)
  4. 选举leader
    public synchronized void start() {
        // 如果不在peer列表中,抛异常
        if (!getView().containsKey(myid)) {
            throw new RuntimeException("My id " + myid + " not in the peer list");
         }
        // 加载zk数据库
        loadDataBase();
        // 启动连接服务端
        startServerCnxnFactory();
        try {
            adminServer.start();
        } catch (AdminServerException e) {
            LOG.warn("Problem starting AdminServer", e);
            System.out.println(e);
        }
        // 启动之后马上进行选举,主要是创建选举必须的环境,比如:启动相关线程
        startLeaderElection();

        // 执行选举逻辑
        super.start();
    }

zk的选举是一个非常复杂且重要的过程,在后面博客中会专门介绍。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值