前言

之前的Zookeeper协议篇-Paxos算法与ZAB协议通过了解Paoxs算法开始,到Zab协议的两大特性:崩溃恢复消息广播,学习了Zookeeper是如何通过Zab协议实现高可用,本篇主要解析Zookeeper的启动流程

单机模式启动流程

我们知道,Zookeeper使用中分为单机和集群两种,而这两种最大的不同则是,集群启动下需要进行Leader选举以及Leader和Follower之间的数据同步操作,而单机启动则不需要此操作,Zookeeper单机启动大概分为三个部分,分别为预处理初始化注册,接下来我们分别来看看三个流程的步骤

预处理

预处理操作中,将创建服务实例之前需要的数据读取加载准备就绪,大体流程如下:

1.首先我们在使用zkServer.sh或者zkServer.cmd这两个脚本启动Zookeeper的时候,默认会启动 org.apache.zookeeper.server.quorum.QuorumPeerMain类,因此无论是Zookeeper的单机还是集群环境下, QuormPeerMain类都是作为默认的入口启动类启动。

2.启动后就会开始解析Zoo.cfg配置文件,从中读取默认配置的tickTimedataDirclientPort

3.当配置读取并解析完毕以后,会创建 DatadirCleanupManager类实例,此类是Zookeeper从3.4版本开始加入的对历史记录文件进行清理以及定时清理日志和快照的管理器

4.从刚刚读取解析的Zoo.cfg配置文件内容中找到clientPort参数内容,通过配置的地址判断是否存在多个地址来确定当前启动的模式是单机版还是集群模式,如果当前启动模式为单机模式,将进入单机的启动流程,并且读取Zoo.cfg剩余的配置信息

5.通过解析Zoo.cfg中的配置信息相关的参数,开始创建ZookeeperServer类实例,完成了这一步后,预处理阶段完成

初始化

初始化阶段,则是开始将Zookeeper中的相关服务管理类进行创建,大体流程如下:

1.创建了ZookeeperServer实例后,Zookeeper会创建一个ServerStats实例,此类用来收集Zookeeper运行过程中的统计信息,例如发送客户端的响应包次数,收到的请求包次数,最近启动后最大的延迟和最小延迟等

2.紧接着会创建Zookeeper中的数据存储管理器--FileTxnSnaplog类,此类作为最上层的,提供了一系列了操作数据文件的接口,其中包括操作事务日志和操作快照的接口,而创建当前类实例会根据zoo.cfg中的dataDir以及dataLogDir参数进行构建

3.同样根据解析出来的zoo.cfg配置文件中的tickTime以及session的会话时间来设置对应参数,并且会根据zookeeper.serverCnxnFactory参数来确定启动Zookeeper的网络连接工厂是基于Netty的还是基于jdk自身的Nio工厂

4.确定工厂类型后,Zookeeper会开始初始化一个Thread,作为整个Zookeeper运行过程中的主线程,并且开始初始化ServerCnxnFactory实例

5.当ServerCnxnFactory实例构建完毕后,开始运行对应的run方法中的业务逻辑,此时由于连接工厂已经创建,端口其实已经对外开放了,但是Zookeeper此时还未完成启动过程,还无法对外处理请求

6.开始恢复Zookeeper的数据,将从事务日志以及之前保存的快照进行数据恢复

7.数据恢复完成后,Zookeeper开始构建会话管理器--SessionTracker,此类主要负责管理Session,在创建的时候,将e xpirationlnterval, nextExpirationTimesessionsWithTimeout进行计算以及配置,并且会计算出每一个Session对应的SessionID,并且在运行过程中会负责Session的会话超时检测等

8.创建完毕后,Zookeeper会初始化对应的请求过滤链,而在Zookeeper中请求的过滤链使用了责任链模式,其中处理的顺序流程主要是PrepRequestProessor->SyncRequestProessor->FinalRequestProessor三个请求处理器,至此Zookeeper的初始化流程已经做完

注册提供服务

当Zookeeper的初始化流程完成后,服务器已经开始到就绪状态了,只需要将对应的信息注册以后即可对外提供服务了,此阶段的流程大概如下:

可以看到此阶段中,Zookeeper只需要将JMX服务注册,以及当前相关实例注册完毕,即可完成单机启动流程,此时的Zookeeper已经正常提供服务了

集群模式启动流程

集群模式的启动过程很多和单机模式是一样的,但是由于集群模式下,会有Leader机器选举以及数据同步的过程,因此Zookeeper的集群模式启动过程要复杂的多,而整个集群的启动过程,大体可以分为五个部分,分别是预处理初始化Leader选举Leader与Follower交互以及Leader与Follower启动,其中预处理过程几乎与单机模式一样,唯一的区别在于解析zoo.cfg中的连接配置,判断启动模式为集群模式,开始进入集群模式的初始化操作流程而已,因此,我们从集群模式的初始化开始

初始化

初始化过程大体和单机模式差不多,如下:

1.创建并初始化ServerCnxnFactory

2.创建Zookeeper中的数据文件管理器FileTxnSnaplog

3.在集群模式下,会去创建QuorumPeer实例,Quorum是集群模式下特有的对象,属于Zookeeper的托管者,此类的作用是在运行期间,会不停的检测当前服务器实例的状态,并且在需要选举的时候发起选举

4.创建Zookeeper中的内存数据库ZKDatabase实例,用来记录会话记录以及DataTree和事物日志

5.QuorumPeer实例作为托管者,会在启动过程中,将核心组件信息注册上去,包括之前创建的ZKDatabase、FileTxnSnaplog以及服务器列表信息,选举算法等

6.开始恢复数据

7.数据恢复完成后,开始启动ServerCnxnFactory中的主线程,运行run方法,开始执行服务器选举相关的操作

Leader选举

选举阶段的流程大概如下:

1.Zookeeper解析zoo.cfg配置文件中的 electionAlg属性,来确定进行选举的算法是哪一种,在Zk中有三种选举算法,分别是 LeaderElectionAuthFastLeaderElectionFastLeaderElection,分别对应数值0-3,不过从3.4的版本开始,zk仅支持FastLeaderElection选举算法,其他两种被废弃了。同样的,在选举的初始化阶段,zk会根据自身服务器ID、lastLoggedZxid和当前服务器的epoch初始化一个选举的票据

2.选举初始化准备好以后,开始注册JMX服务

3.前面创建好的QuorumPeer实例会不断检测当前的服务器状态,在正常情况下,QuorumPeer的状态应该是LOOKING,才会开始进行选举操作

4.开始进行选举操作,简单来说,zk中一般是ZXID最大的机器成为Leader,如果ZXID一样,SID越大的则成为Leader。(zk的详细选举流程,则在后续的文章中分析)

Leader与Follower交互

当选举出Leader机器以后,其他的机器则会开始与Leader进行交互,进行数据同步等操作,此阶段的流程大致如下:

1.不同角色(Leader和Follower)的zookeeper服务器在选举完毕后,会开始进入各自角色的主流程

2.在Zookeeper集群运行期间,Leader服务器需要和其他的服务器保持连接确定集群的机器存活情况,zk创建LearnerCnxAcceptor实例用来负责处理所有的非Leader机器的连接请求

3.非Leader服务器在启动完毕后,会从选举的结果中找到集群的Leader,并且尝试进行连接

4.Leader的LearnerCnxAcceptor实例在接受到非Leader机器的请求后,会创建LearnerCnxHandler实例,每个实例会对应一个Leader与非Leader机器的连接,负责对应服务器之间的消息通信处理以及数据同步操作

5.当非Leader机器与Leader服务器建立连接后,非Leader机器就会将自己的信息发送给Leader,此过程的数据称之为LearnerInfo,其中包括了当前服务器的SID以及最大的ZXID

6.Leader收到LearnerInfo消息后,从中解析出SID和ZXID,然后根据ZXID解析出epochoflearner,和Leader自身的epochofleader进行比较,如果发现Leader的epochofleader比较小,则会更新Leader的epoch:

  1. epoch_of_leader = epoch_of_learner + 1

然后继续等待其他机器的LearnerInfo消息,直到半数以上,即可确定整个集群中的epoch值了

7.在确定了epoch以后,Leader将该信息发送给所有的非Leader机器,此消息称之为LEADERINFO

8.Follower机器在收到Leader发送的LEADERINFO消息后,解析出消息中的epochZXID,然后响应给Leader一个ack

9.Leader收到ack以后,就可以开始与该Follower机器进行数据同步过程了

10.整个集群中如果超过半数的Follower机器完成了和Leader之间的数据同步过程,这个时候集群实例就已经可以提前启动对外提供服务

Leader和Follower启动

集群模式下的Zookeeper在完成了Leader与Follower服务器之间的交互流程后,也开始进入到了启动注册的阶段,此阶段和单机模式流程几乎相同,首先是创建并且启动会话管理器,然后初始化Zookeeper中的请求处理链,接着Zookeeper开始注册JMX服务,当注册完毕后,整个集群的启动完成,此时Zookeeper的集群也可以对外开始提供服务了

Zookeeper启动流程分析的更多相关文章

  1. Storm集群启动流程分析

    Storm集群启动流程分析 程序员 1.客户端运行storm nimbus时,会调用storm的python脚本,该脚本中为每个命令编写了一个方法,每个方法都可以生成一条相应的Java命令. 命令格式 ...

  2. u-boot启动流程分析(2)_板级(board)部分

    转自:http://www.wowotech.net/u-boot/boot_flow_2.html 目录: 1. 前言 2. Generic Board 3. _main 4. global dat ...

  3. u-boot启动流程分析(1)_平台相关部分

    转自:http://www.wowotech.net/u-boot/boot_flow_1.html 1. 前言 本文将结合u-boot的“board—>machine—>arch—> ...

  4. Cocos2d-x3.3RC0的Android编译Activity启动流程分析

    本文将从引擎源代码Jni分析Cocos2d-x3.3RC0的Android Activity的启动流程,以下是具体分析. 1.引擎源代码Jni.部分Java层和C++层代码分析 watermark/2 ...

  5. Netty 拆包粘包和服务启动流程分析

    Netty 拆包粘包和服务启动流程分析 通过本章学习,笔者希望你能掌握EventLoopGroup的工作流程,ServerBootstrap的启动流程,ChannelPipeline是如何操作管理Ch ...

  6. Uboot启动流程分析(转载)

    最近一段时间一直在做uboot移植相关的工作,需要将uboot-2016-7移植到单位设计的ARMv7的处理器上.正好元旦放假三天闲来无事,有段完整的时间来整理下最近的工作成果.之前在学习uboot时 ...

  7. 【转】Netty 拆包粘包和服务启动流程分析

    原文:https://www.cnblogs.com/itdragon/archive/2018/01/29/8365694.html Netty 拆包粘包和服务启动流程分析 通过本章学习,笔者希望你 ...

  8. ubuntu为什么没有/etc/inittab文件? 深究ubuntu的启动流程分析

    Linux 内核启动 init ,init进程ID是1,是所有进程的父进程,所有进程由它控制. Ubuntu 的启动由upstart控制,自9.10后不再使用/etc/event.d目录的配置文件,改 ...

  9. imx6 uboot启动流程分析

    参考http://blog.csdn.net/skyflying2012/article/details/25804209 这里以imx6平台为例,分析uboot启动流程对于任何程序,入口函数是在链接 ...

随机推荐

  1. 23、Interpreter 解释器模式

    1.Interpreter 解释器模式 解释器模式是一种使用频率相对较低但学习难度较大的设计模式,它用于描述如何使用面向对象语言构成一个简单的语言解释器.在某些情况下,为了更好地描述某一些特定类型的问 ...

  2. 比原链CTO James | Go语言成为区块链主流开发语言的四点理由

    11月24日,比原链CTO James参加了Go中国举办的Gopher Meetup杭州站活动,与来自阿里.网易的技术专家带来Kubernetes.区块链.日志采集.云原生等话题的分享.James向大 ...

  3. Oracle 存储过程 批量插入测试数据

    有时候需要做DB的效率测试时,需要模拟大量数据.可以根据一条原始数据,通过执行存储过程拷贝出大量数据: CREATE OR REPLACE PROCEDURE proc_msw_strsql IS i ...

  4. 图数据库HugeGraph源码解读 (1) —— 入门介绍

    HugeGraph介绍 以下引自官方文档: HugeGraph是一款易用.高效.通用的开源图数据库系统(Graph Database,GitHub项目地址), 实现了Apache TinkerPop3 ...

  5. C#LeetCode刷题之#459-重复的子字符串(Repeated Substring Pattern)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3945 访问. 给定一个非空的字符串,判断它是否可以由它的一个子串 ...

  6. C#图解教程(第四版)—01—类型,存储,变量

    3.1 如何广泛的描述C#程序 可以说C程序是一组函数和数据类型,C++程序是一组函数和类,然而C#程序是一组类型声明 3.2 类型 可以把类型想象成一个用来创建数据结构的模板,模板本身并不是数据结构 ...

  7. Mybatis-09-缓存

    缓存 什么是缓存[Cache]? 存在内存中的临时数据 提高查询效率,解决高并发的性能问题 为什么使用缓存? 减少和数据库的交互次数,减少系统开销,提高系统效率 什么样的数据能使用缓存? 经常查询且不 ...

  8. 精讲RestTemplate第10篇-使用代理作为跳板发送请求

    本文是精讲RestTemplate第10篇,前篇的blog访问地址如下: 精讲RestTemplate第1篇-在Spring或非Spring环境下如何使用 精讲RestTemplate第2篇-多种底层 ...

  9. 关于Java中for循环的i++和++i区别

    我们应该都知道i++和++i的区别是: ++i是先执行 i = i +1 再使用 i 的值,而 i++ 是先使用 i 的值再执行 i = i + 1: for循环的执行顺序如下: for(a;b;c) ...

  10. eclipse git如何切换分支,拉取代码,合并代码,解决冲突等

    (如果想看eclipse拉取git项目,移步到我上一篇文章)以下步骤是eclipse运用git的切换分支,拉取合并代码的基本操作: 1.切换远程分支:鼠标右键项目--team--switch to - ...