【Zookeeper源码走读】第二章 服务器的启动过程

这篇具有很好参考价值的文章主要介绍了【Zookeeper源码走读】第二章 服务器的启动过程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Server启动的流程

通过运行zk的启动脚本,找到zk服务器端的入口类。脚本如下:

    ZOOMAIN="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=$JMXLOCALONLY org.apache.zookeeper.server.quorum.QuorumPeerMain"

所以,zk的入口类是 QuorumPeerMain,以下是该类的 main() 方法的完整代码:

    public static void main(String[] args){
        QuorumPeerMain main=new QuorumPeerMain();
        try{
            main.initializeAndRun(args);
        }catch(IllegalArgumentException e){
            ......
        }
        LOG.info("Exiting normally");
    }

跟踪方法中的initializeAndRun(),代码如下:

    protected void initializeAndRun(String[] args) throws ConfigException, IOException, AdminServerException {
        QuorumPeerConfig config = new QuorumPeerConfig();
        if (args.length == 1) {
            config.parse(args[0]);
        }

        // Start and schedule the purge task
        DatadirCleanupManager purgeMgr = new DatadirCleanupManager(
        config.getDataDir(),
        config.getDataLogDir(),
        config.getSnapRetainCount(),
        config.getPurgeInterval());
        purgeMgr.start();

        if (args.length == 1 && config.isDistributed()) {
            runFromConfig(config);
        } else {
            LOG.warn("Either no config or no quorum defined in config, running in standalone mode");
            // there is only server in the quorum -- run as standalone
            ZooKeeperServerMain.main(args);
        }
    }

方法中,继续跟踪 ZooKeeperServerMain.main(args),代码如下:

    public static void main(String[] args) {
        System.out.println(System.getProperty("log4j.configuration"));
        ZooKeeperServerMain main = new ZooKeeperServerMain();
        try {
            main.initializeAndRun(args);
        } catch (IllegalArgumentException e) {
            ......
        }
        LOG.info("Exiting normally");
        ServiceUtils.requestSystemExit(ExitCode.EXECUTION_FINISHED.getValue());
    }

上面的代码就是初始化ZooKeeperServerMainmain对象,然后调用initializeAndRun()方法:

    protected void initializeAndRun(String[] args) throws ConfigException, IOException, AdminServerException {
        try {
            ManagedUtil.registerLog4jMBeans();
        } catch (JMException e) {
            LOG.warn("Unable to register log4j JMX control", e);
        }

        ServerConfig config = new ServerConfig();
        if (args.length == 1) {
            config.parse(args[0]);
        } else {
            config.parse(args);
        }

        runFromConfig(config);
    }

总结一下就是: QuorumPeerMain.initializeAndRun()->ZooKeeperServerMain.initializeAndRun(),然后initializeAndRun()调用runFromConfig()方法,如下:

    public void runFromConfig(ServerConfig config) throws IOException, AdminServerException {
        LOG.info("Starting server");
        ......
        // 不影响流程的代码删掉了
            final ZooKeeperServer zkServer = new ZooKeeperServer(jvmPauseMonitor, txnLog, config.tickTime, config.minSessionTimeout, config.maxSessionTimeout, config.listenBacklog, null, config.initialConfig);
                    txnLog.setServerStats(zkServer.serverStats());
    
            // Registers shutdown handler which will be used to know the
            // server error or shutdown state changes.
            final CountDownLatch shutdownLatch = new CountDownLatch(1);
                    zkServer.registerServerShutdownHandler(new ZooKeeperServerShutdownHandler(shutdownLatch));

            // Start Admin server
            adminServer = AdminServerFactory.createAdminServer();
            adminServer.setZooKeeperServer(zkServer);
            adminServer.start();

            boolean needStartZKServer = true;
            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;
            }
            if (config.getSecureClientPortAddress() != null) {
                secureCnxnFactory = ServerCnxnFactory.createFactory();
                secureCnxnFactory.configure(config.getSecureClientPortAddress(), config.getMaxClientCnxns(), config.getClientPortListenBacklog(), true);
                secureCnxnFactory.startup(zkServer, needStartZKServer);
            }
    
            containerManager = new ContainerManager(
                zkServer.getZKDatabase(),
                zkServer.firstProcessor,
                Integer.getInteger("znode.container.checkIntervalMs", (int) TimeUnit.MINUTES.toMillis(1)),
                Integer.getInteger("znode.container.maxPerMinute", 10000),
                Long.getLong("znode.container.maxNeverUsedIntervalMs", 0)
            );
            containerManager.start();
            ZKAuditProvider.addZKStartStopAuditLog();
			......
			// shutdown 相关的代码也被删掉了
    }

上面那么多的代码,只需要关注这一段即可:

    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;
    }

查看 cnxnFactory 的创建方法:

    public static ServerCnxnFactory createFactory() throws IOException {
        String serverCnxnFactoryName = System.getProperty(ZOOKEEPER_SERVER_CNXN_FACTORY);
        if (serverCnxnFactoryName == null) {
            serverCnxnFactoryName = NIOServerCnxnFactory.class.getName();
        }
        try {
            ServerCnxnFactory serverCnxnFactory = (ServerCnxnFactory) Class.forName(serverCnxnFactoryName)
            .getDeclaredConstructor()
            .newInstance();
            LOG.info("Using {} as server connection factory", serverCnxnFactoryName);
            return serverCnxnFactory;
        } catch (Exception e) {
            IOException ioe = new IOException("Couldn't instantiate " + serverCnxnFactoryName, e);
            throw ioe;
        }
    }

由上面的代码可知,默认是使用的NIOServerCnxnFactory类,接下来跟踪NIOServerCnxnFactory.startup()方法:

    public void startup(ZooKeeperServer zks, boolean startServer) throws IOException, InterruptedException {
        start();
        setZooKeeperServer(zks);
        if (startServer) {
            zks.startdata();
            zks.startup();
        }
    }

查看第一行代码:

    public void start() {
        stopped = false;
        if (workerPool == null) {
            workerPool = new WorkerService("NIOWorker", numWorkerThreads, false);
        }
        for (SelectorThread thread : selectorThreads) {
            if (thread.getState() == Thread.State.NEW) {
                thread.start();
            }
        }
        // ensure thread is started once and only once
        if (acceptThread.getState() == Thread.State.NEW) {
            acceptThread.start();
        }
        if (expirerThread.getState() == Thread.State.NEW) {
            expirerThread.start();
        }
    }

注意这里,方法内部是启动多个线程,比如:acceptThread是接收socket的线程(AcceptThread),acceptThread的初始化是在NIOServerCnxnFactory.configure()中实现的:

@Override
    public void configure(InetSocketAddress addr, int maxcc, int backlog, boolean secure) throws IOException {
        ......
        acceptThread = new AcceptThread(ss, addr, selectorThreads);
    }

NIOServerCnxnFactory.configure() 先于 NIOServerCnxnFactory.startup() 执行,所以,在NIOServerCnxnFactory.startup() 中可直接启动acceptThread的start

然后跟踪最后一行代码,zks.startup():

    public synchronized void startup() {
        startupWithServerState(State.RUNNING);
    }

    private void startupWithServerState(State state) {
        if (sessionTracker == null) {
            createSessionTracker();
        }
        startSessionTracker();
        setupRequestProcessors();

        startRequestThrottler();

        registerJMX();

        startJvmPauseMonitor();

        registerMetrics();

        setState(state);

        requestPathMetricsCollector.start();

        localSessionEnabled = sessionTracker.isLocalSessionsEnabled();

        notifyAll();
    }

startupWithServerState() 方法里面就是启动各种线程。目前未详细了解每个线程的用途,暂时不关注。

至此,服务器端的启动流程大致完成了,一些细节的东西,待后面深入后再细究。文章来源地址https://www.toymoban.com/news/detail-435563.html

到了这里,关于【Zookeeper源码走读】第二章 服务器的启动过程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【云原生进阶之PaaS中间件】第二章Zookeeper-3.2架构详解

    » 领导者(leader),负责进行投票的发起和决议,更新系统状态 » 学习者(learner),包括跟随者(follower)和观察者(observer),follower用于接受客户端请求并想客户端返回结果,在选主过程中参与投票 » Observer可以接受客户端连接,将写请求转发给leader,但observer不参加投票

    2024年02月08日
    浏览(56)
  • 《凤凰架构》第二章——访问远程服务

    这章挺难的,感觉离我比较远,不太好懂,简单记录吧。 这章主要讲访问远程服务,主要对比了RPC和REST的区别,可以结合知乎上的文章《既然有 HTTP 请求,为什么还要用 RPC 调用?》 这篇文章进行理解。 而对于远程服务调用,它的内容不单单只有REST、RPC,还有像SOAP,WebS

    2024年02月11日
    浏览(47)
  • 第二章 Eureka服务注册与发现

    gitee:springcloud_study: springcloud:服务集群、注册中心、配置中心(热更新)、服务网关(校验、路由、负载均衡)、分布式缓存、分布式搜索、消息队列(异步通信)、数据库集群、分布式日志、系统监控链路追踪。 1. Eureka基础知识 什么是服务治理? 在传统的rpc远程调用框

    2024年02月03日
    浏览(54)
  • 《微服务架构设计模式》第二章

    软件架构的定义 看一下大佬是怎么说的: 计算机系统的软件架构是构建这个系统所需要的一组结构,包括软件元素、它们之间的关系以及两者的属性。 --Bass等著《Documenting Software Architectures:Views and Beyond》 这个定义将软件分解为元素和元素之间的关系两个部分,就像一辆汽车

    2024年02月09日
    浏览(43)
  • 《微服务架构设计模式》第二章 服务的拆分策略

    内容总结自《微服务架构设计模式》 软件架构的定义:计算机系统的软件架构是构建这个系统所需要的一组结构,包括软件元素、他们之间的关系以及两者的属性(Bass等著) 其实质是应用程续的架构将软件分解为元素(element)和这些元素之间的关系(relation)。由于这两个

    2024年02月09日
    浏览(40)
  • 第二章 SpringCloud Alibaba 微服务环境搭建

    我们本次是使用的电商项目中的商品、订单、用户为案例进行搭建。 技术选型 maven:3.3.9 数据库:MySQL 5.7 持久层: SpingData Jpa 其他: SpringCloud Alibaba 技术栈 模块设计 springcloud-alibaba 父工程 shop-common 公共模块【实体类】 shop-user 用户微服务 【端口: 807x】 shop-product 商品微服务 【

    2024年02月04日
    浏览(49)
  • 第二章 系统集成及服务管理知识点1

    这第二章主要讲了下集成及服务管理的内容、制度、意义、管理办法、以及一些管理方面的服务概念。跟着小老弟把内容给归纳归纳,后面来复习的时候也能够省不少时间! 1信息系统集成及服务管理的内容 在信息化建设过程中,系统集成及服务存在了诸多问题,主要问题:

    2024年02月16日
    浏览(39)
  • deeplabv3+源码之慢慢解析 第二章datasets文件夹(1)voc.py--voc_cmap函数和download_extract函数

    第一章deeplabv3+源码之慢慢解析 根目录(1)main.py–get_argparser函数 第一章deeplabv3+源码之慢慢解析 根目录(2)main.py–get_dataset函数 第一章deeplabv3+源码之慢慢解析 根目录(3)main.py–validate函数 第一章deeplabv3+源码之慢慢解析 根目录(4)main.py–main函数 第一章deeplabv3+源码之慢慢解析 根目

    2024年02月13日
    浏览(52)
  • 第二章(第二节):无穷小量和函数

    若 lim f(x) = 0 , 则称函数 f(x) 当 x → x 0 时是无穷小量,简称: 无穷小 。      x→ x 0 定理1. 有限多个 无穷小量的代数和仍是无穷小量 定理2. 有限多个 无穷小量的积也是无穷小量 定理3.常数与无穷小量的积也是无穷小量 定理4.有界变量与无穷小量的积是无穷小量 当 x→

    2024年02月08日
    浏览(53)
  • 第二章 翻译

    Section Ⅲ Translation Directions: In this section, there is a text in English. Translate it into Chinese. Write your translation on ANSWER SHEET 2. (15points) “Sustainability” has become a popular word these days, but to Ted Ning, the concept will always have personal meaning. Having endured a painful period of unsustainability in his own life made it

    2024年02月08日
    浏览(66)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包