暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

zookeeper服务端启动流程

Java Miraculous 2021-08-26
1305
上一篇文章中说要分析zookeeper(以下简称zk)是如何保证一致性的,在这之前,我们得先熟悉下源码。
  • 一、源码

  • 1.1、源码下载

下载地址:https://github.com/apache/zookeeper.git
  • 1.2、源码介绍

  • 1.3、maven执行install

运行命令:mvn -DskipTests clean install -U

:建议跳过test,不然需要很长时间,另外有些包是provider的,在打包时候不会打进去,所以需要改下,不然启动的时候会报class not found,这些依赖如下:
    <dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-server</artifactId>
    <!--<scope>provided</scope>-->
    </dependency>
    <dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-servlet</artifactId>
    <!--<scope>provided</scope>-->
    </dependency>
    <dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-client</artifactId>
    <!--<scope>provided</scope>-->
    </dependency>
    <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <!--<scope>provided</scope>-->
    </dependency>
    <dependency>
    <groupId>io.dropwizard.metrics</groupId>
    <artifactId>metrics-core</artifactId>
    <!--<scope>provided</scope>-->
    </dependency>
    <dependency>
    <groupId>org.xerial.snappy</groupId>
    <artifactId>snappy-java</artifactId>
    <!--<scope>provided</scope>-->
        </dependency>
    复制
    • 二、源码调试

    zk服务端的启动入口是QuorumPeerMain类中的main方法

    zk是java开发的,但是不知道你们有没有发现一个问题,我们在利用jps查看java的进程的时候,并没有发现zookeeper字样的进程,其实zk的进程名就是QuorumPeerMain

    下面就从QuorumPeerMain类入手看看zkServer的启动流程

    接下来看initializeAndRun方法

    • 2.1、解析参数

    这个参数其实就是zk的配置文件,我们需要给它指定了

      VM options:
      -Dlog4j.configuration=file:conf\log4j.properties
      Program arguments:
      conf\zoo_sample.cfg
      复制
      :日志文件的位置也得指定,不然启动后控制台看不到日志

      记不记得我们在linux中安装zk的时候,做的一步操作是把zoo_sample.cfg复制一份改成zoo.cfg,然后我们就可以通过./zkServer.sh start启动zk了,如果不做这步操作,那启动的时候需要指定配置文件./zkServer.sh start ../conf/zoo_sample.cfg,为什么?我们去linux上看下zkServer.sh这个启动脚本里的内容

      vi zkServer.sh

      vi zkEnv.sh

      因为我们这是源码调试,不用启动脚本,所以需要指定下配置文件的位置,不管改不改名字都得指定,那我索性不改了。
      附zoo_sample.cfg的部分内容,忘记含义的可以再温习下
        # 心跳时间,用于配置服务器最小时间的单位,默认值3000ms,心跳检测时间通常是该单位的倍数。如客户端与服务端之间的会话超时时间在2tickTime~20tickTime之间
        tickTime=2000
        # 用于配置leader服务器等待Follewer服务器启动,并完成数据同步的时间,默认为10,表示10*tickTime
        initLimit=10
        # 用于配置leader服务器和Follewer服务器之间进行心跳检测的最大延时时间,默认为5,表示5*tickTime
        syncLimit=5
        # 用于配置zookeeper服务器存储快照文件(zookeeper 节点数据)的目录,无默认值
        dataDir=conf/data
        # 用于配置服务器存储事务日志文件的目录,有默认值dataDir,但是建议将两个目录分别配置,防止磁盘的并发读写,影响服务器性能。可将其配置在一个单独的磁盘上
        #dataLogDir=
        # 用于配置当前服务器对客户端暴露的端口,一般配置为2181,无默认值
        clientPort=2182
        # 从socket层面限制单个客户端和单台服务器之间的最大并发连接数,即以IP地址粒度来进行连接数的限制,如果为0,表示不作限制,默认为60
        #maxClientCnxns=60
        # 这个参数和autopurge.purgeInterval搭配使用,这个参数指定了需要保留的文件数目。默认是保留3个
        autopurge.snapRetainCount=3
        # Purge task interval in hours
        # 3.4.0及之后版本,ZK提供了自动清理事务日志和快照文件的功能,这个参数指定了清理频率,单位是小时,需要配置一个1或更大的整数,默认是0,表示不开启自动清理功能
        autopurge.purgeInterval=1
        复制
        debug看下,解析到的配置:

        注:为了避开默认值的干扰,这里将端口修改为2182,证明配置加载正常

        • 2.2、数据清理器DatadirCleanupManager

        DatadirCleanupManager的作用是清理多余的快照文件和事务日志文件,下面看下的它工作原理
        • 2.2.1、初始化一个DatadirCleanupManager

        从上图可以看出,构造好的DatadirCleanupManager对象里有6个参数:
        purgeTaskStatus:表示数据清理器的工作状态,初始化的时候是NOT_STARTED,表示未启动
        timer:数据清理器内部开启的定时器,因为是定时清理,所以需要一个定时器
        snapDir:取自配置文件中的dataDir,用于配置zookeeper服务器存储快照文件(zookeeper 节点数据)的目录,无默认值
        dataLogDir:取自配置文件中的dataLogDir,用于配置服务器存储事务日志文件的目录,有默认值dataDir,但是建议将两个目录分别配置,防止磁盘的并发读写,影响服务器性能。可将其配置在一个单独的磁盘上
        snapRetainCount:取自配置文件中的autopurge.snapRetainCount,不配置的话默认是3
        purgeInterval:取自配置文件中的autopurge.purgeInterval,不配置的话,默认是0,表示不开启自动清理功能
        • 2.2.2、启动DatadirCleanupManager

        程序继续往下调用DatadirCleanupManager的start方法,进入start方法

        从上图可以看到,purgeInterval这个参数对数据清理器的开启起决定性作用,为了演示开启的功能,我们把这个参数设置为1,表示一小时清理一次,重新来debug

        我们都知道,开启一个定时器就是为了执行定时任务里的逻辑,所以PurgeTask里run方法其实就是核心逻辑了,看下PurgeTask类

        下面我们主要看PurgeTxnLog.purge方法就可以了,因为这里是定时执行的任务

        2.2.2.1、校验并创建事务日志文件目录和数据快照文件目录

        这块就不细说了,很简单,就是创建这两个文件夹,然后校验下这两个文件夹有没有创建成功,有没有对这两个文件夹的写权限等,默认生成的文件夹名字是version-2,

        可以上linux上看下这个文件夹里的内容(因为我的linux上的zk中有数据)

        2.2.2.2、找到要清理的文件findNValidSnapshots

        2.2.2.3、清理文件purgeOlderSnapshots


        :getSnapshotLogs方法返回的是要保留的log文件

        • 2.3、执行启动流程

        由上图可知,只要符合不是单机运行或者选举的成员个数大于1这两个条件中的其中一个,就表示集群模式,这里显然是以单机模式运行

        • 2.3.1、分析单机模式的启动

        进入ZooKeeperServerMain.main方法,点进去后你会发现

        接下来的runFromConfig方法就是主要方法了

        下面说下绑定端口这一块
          if (config.getClientPortAddress() != null) {
          cnxnFactory = ServerCnxnFactory.createFactory();
          cnxnFactory.configure(config.getClientPortAddress(), config.getMaxClientCnxns(), config.getClientPortListenBacklog(), false);
          cnxnFactory.startup(zkServer);
          zkServer has been started. So we don't need to start it again in secureCnxnFactory.
          needStartZKServer = false;
          }
          复制
          先是创建NIOServerCnxnFactory对象,服务端每收到客户端的一个请求就会创建一个ServerCnxn对象,Zookeeper用nio或netty进行客户端与服务端的绑定,默认是NIOServerCnxnFactory

          然后调用startup方法

          最后,启动成功

          用客户端连接上操作下数据

          写点数据进去

          可以看到在version-2目录中生成了log文件和快照文件

          • 2.3.2、分析集群模式的启动

          它的ZAB协议就是在集群模式中实现的,篇幅原因,下篇文章见。
          文章转载自Java Miraculous,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

          评论