zookeeper 协调hiveserver2 zookeeper.server.principal_zookeeper

预启动

1、统一由 QuorumPeerMain 作为启动类。

     无论是单机版还是集群模式启动Zookeeper服务器,QuorumPeerMain 都作为启动入口。

2、解析配置文件Zoo.cfg

     首先会创建 QuorumPeerConfig 并解析配置文件(zoo.cfg)。该文件包括 tickTime 、dataDir 和 clientPort等参数。

3、创建并启动历史文件清理器 DatadirCleanupManager

4、判断是单机模式还是集群模式,此处分析单机版模式,会委托给 ZooKeeperServerMain 进行处理

5、创建ServerConfig并进行配置文件的再次解析

public class ZooKeeperServerMain {
    public static void main(String[] args) {
        ZooKeeperServerMain main = new ZooKeeperServerMain();
        
        //省略部分代码

        main.initializeAndRun(args);
    }

    protected void initializeAndRun(String[] args)
        throws ConfigException, IOException
    {
        ServerConfig config = new ServerConfig();
        
        //配置文件的解析入口
        if (args.length == 1) {
            config.parse(args[0]);
        } else {
            config.parse(args);
        }

        runFromConfig(config);
    }
}

当args.length == 1时,其实args[0] 就表示配置文件的path,内部会委托给 QuorumPeerConfig 进行解析

当args.length != 1 时

/**
     * Parse arguments for server configuration
     * @param args clientPort dataDir and optional tickTime
     * @return ServerConfig configured wrt arguments
     * @throws IllegalArgumentException on invalid usage
     */
    public void parse(String[] args) {
        if (args.length < 2 || args.length > 4) {
            throw new IllegalArgumentException("Invalid args:"
                    + Arrays.toString(args));
        }

        clientPortAddress = new InetSocketAddress(Integer.parseInt(args[0]));
        dataDir = args[1];
        dataLogDir = dataDir;
        if (args.length == 3) {
            tickTime = Integer.parseInt(args[2]);
        }
        if (args.length == 4) {
            maxClientCnxns = Integer.parseInt(args[3]);
        }
    }

6、创建服务器实例ZookeeperServer

ZookeeperServer是单机版Zookeeper服务端最核心的实体类。

初始化阶段

1、创建服务器的统计器ServerStats

ServerStats 是 Zookeeper 服务器运行时统计器,包含了最基本的运行时信息。

/**
 * Basic Server Statistics
 * //从Zookeeper启动开始或者是最近一次重置服务端统计信息 之后开始进行统计
 */
public class ServerStats {
    //服务端向客户端发送的响应包数
    private long packetsSent;

    //服务端接收到的来自客户端的请求包数
    private long packetsReceived;

    //服务端请求处理最 大延时
    private long maxLatency;
    
    //服务端请求处理最 小延时
    private long minLatency = Long.MAX_VALUE;

    //服务端请求处理 总延时
    private long totalLatency = 0;

    //服务端处理的客户端请求总数
    private long count = 0;

    //省略部分代码
}

2、创建Zookeeper数据管理器 FileTxnSnapLog

FileTxnSnapLog是Zookeeper上层服务器和底层数据存储之间的对接层,正如源码中所说 This is a helper class ,提供了一系列操作文件的接口,包括事务日志文件和快照数据文件。根据zoo.cfg里面的dataDir(快照数据文件),dataLogDir(事务日志文件)来创建FileTxnSnapLog

3、设置服务器tickTime和会话超时时间限制

zkServer.setTickTime(config.tickTime);
 zkServer.setMinSessionTimeout(config.minSessionTimeout);
 zkServer.setMaxSessionTimeout(config.maxSessionTimeout);

4、创建 ServerCnxnFactory 

      可以通过 zookeeper.serverCnxnFactory 来指定使用NIOServerCnxnFactory 还是 NettyServerCnxnFactory 

5、初始化ServerCnxnFactory 

       Zookeeper首先会初始化一个线程,作为整个ServerCnxnFactory 的主线程,然后再初始化NIO服务器。

public void configure(InetSocketAddress addr, int maxcc) throws IOException {
        configureSaslLogin();

        thread = new Thread(this, "NIOServerCxn.Factory:" + addr);
        thread.setDaemon(true);
        maxClientCnxns = maxcc;
        this.ss = ServerSocketChannel.open();
        ss.socket().setReuseAddress(true);
        LOG.info("binding to port " + addr);
        ss.socket().bind(addr);
        ss.configureBlocking(false);
        ss.register(selector, SelectionKey.OP_ACCEPT);
    }

6、启动ServerCnxnFactory 主线程

      直接调用线程的start方法启动线程

7、恢复本地数据      

//调用ZookeeperServer的startdata方法恢复数据
public void startdata() 
    throws IOException, InterruptedException {
        //check to see if zkDb is not null
        if (zkDb == null) {
            zkDb = new ZKDatabase(this.txnLogFactory);
        }  
        if (!zkDb.isInitialized()) {
            loadData();
        }
    }

8、创建并启动会话管理器

      在Zookeeper启动时会创建一个会话管理器SessionTracker

public void startup() {        
        if (sessionTracker == null) {
            createSessionTracker();
        }
        startSessionTracker();

        //省略部分代码
    }

 9、初始化Zookeeper的请求处理链

      Zookeeper请求处理是典型的责任链模式,在Zookeeper服务器上,会有多个请求处理器依次来处理客户端的请求

protected void setupRequestProcessors() {
        RequestProcessor finalProcessor = new FinalRequestProcessor(this);
        RequestProcessor syncProcessor = new SyncRequestProcessor(this,
                finalProcessor);
        ((SyncRequestProcessor)syncProcessor).start();
        firstProcessor = new PrepRequestProcessor(this, syncProcessor);
        ((PrepRequestProcessor)firstProcessor).start();
    }

   10、注册JMX服务 

           registerJMX()

    11、注册Zookeeper服务器实例

           NIOServerCnxnFactory 类的方法 setZooKeeperServer(zks);

 

至此,单机版的Zookeeper服务器实例已经启动。