zk源码阅读26:集群版服务器启动概述

摘要

本节结合源码对集群版服务器启动进行概述,流程图如下


集群版服务器启动

主要分为

  预启动
  初始化
  Leader选举(选举算法在之后讲)
  Leader和Follower启动期交互过程
  Leader和Follower启动

这里都是概述,没有详细分析源码,下面几节展开分析

预启动

1. 统一由QuorumPeerMain作为启动类。
2. 解析配置文件zoo.cfg。
3. 创建并启动历史文件清理器DatadirCleanupFactory。
4. 判断当前是集群模式还是单机模式的启动。
    在集群模式中,在zoo.cfg文件中配置了多个服务器地址,可以选择集群启动。

上述代码都在org.apache.zookeeper.server.quorum.QuorumPeerMain#initializeAndRun中,截图如下

预启动的4个步骤

初始化

1. 创建ServerCnxnFactory。
2. 初始化ServerCnxnFactory。
3. 创建Zookeeper数据管理器FileTxnSnapLog。
4. 创建QuorumPeer实例。
    Quorum是集群模式下特有的对象,是Zookeeper服务器实例(ZooKeeperServer)的托管者,QuorumPeer代表了集群中的一台机器
    在运行期间,QuorumPeer会不断检测当前服务器实例的运行状态,同时根据情况发起Leader选举。
5. 创建内存数据库ZKDatabase。
    ZKDatabase负责管理ZooKeeper的所有会话记录以及DataTree和事务日志的存储。
6. 初始化QuorumPeer。
    将核心组件如FileTxnSnapLog、ServerCnxnFactory、ZKDatabase注册到QuorumPeer中,同时配置QuorumPeer的参数,如服务器列表地址、Leader选举算法和会话超时时间限制等。
7. 恢复本地数据。
8. 启动ServerCnxnFactory主线程。

其中1-6步在org.apache.zookeeper.server.quorum.QuorumPeerMain#runFromConfig中,顺序不完全一样

初始化1-6步

7-8步在org.apache.zookeeper.server.quorum.QuorumPeer#start中

    @Override
    public synchronized void start() {
        loadDataBase();//从事务日志目录dataLogDir和数据快照目录dataDir中恢复出DataTree数据
        cnxnFactory.start();//开启对客户端的连接端口,启动ServerCnxnFactory主线程
        startLeaderElection();//创建出选举算法
        super.start();//启动QuorumPeer线程,在该线程中进行服务器状态的检查
    }

leader选举

1. 初始化Leader选举算法

集群模式特有,Zookeeper首先会根据自身的服务器ID(SID)、最新的ZXID(lastLoggedZxid)和当前的服务器epoch(currentEpoch)来生成一个初始化投票
在初始化过程中,每个服务器都会给自己投票。然后,根据zoo.cfg的配置,创建相应Leader选举算法实现
Zookeeper提供了三种默认算法(LeaderElection、AuthFastLeaderElection、FastLeaderElection),可通过zoo.cfg中的electionAlg属性来指定,但现只支持FastLeaderElection选举算法。
在初始化阶段,Zookeeper会创建Leader选举所需的网络I/O层QuorumCnxManager,同时启动对Leader选举端口的监听,等待集群中其他服务器创建连接。

源码在QuorumPeer#startLeaderElection中
完成自己的投票以及投票算法的获取

2.注册JMX服务。

代码在org.apache.zookeeper.server.quorum.QuorumPeer#run中

3.检测当前服务器状态

运行期间,QuorumPeer会不断检测当前服务器状态。在正常情况下,Zookeeper服务器的状态在LOOKING、LEADING、FOLLOWING/OBSERVING之间进行切换。在启动阶段,QuorumPeer的初始状态是LOOKING,因此开始进行Leader选举。

4. Leader选举。

通过投票确定Leader,其余机器称为Follower和Observer。具体算法在后面会给出。
源码体现在org.apache.zookeeper.server.quorum.Election#lookForLeader
默认实现org.apache.zookeeper.server.quorum.FastLeaderElection#lookForLeader

上述步骤在

leader选举步骤源码.png

2-4的源码步骤太长了,这里不贴出来了,就在QuorumPeer#run中

Leader和Follower启动期交互过程

leader和follower服务器启动交互过程

创建Leader服务器和Follower服务器。完成Leader选举后,每个服务器会根据自己服务器的角色创建相应的服务器实例,并进入各自角色的主流程。
源码体现在org.apache.zookeeper.server.quorum.QuorumPeer#run
中switch不同的case

1.Leader服务器启动Follower接收器LearnerCnxAcceptor(leader端)

运行期间,Leader服务器需要和所有其余的服务器(统称为Learner)保持连接以确集群的机器存活情况,LearnerCnxAcceptor负责接收所有非Leader服务器的连接请求。

2.Learner服务器开始和Leader建立连接。(learner端)

所有Learner会找到Leader服务器,并与其建立连接。

3.Leader服务器创建LearnerHandler(leader端)

Leader接收到来自其他机器连接创建请求后,会创建一个LearnerHandler实例,每个LearnerHandler实例都对应一个Leader与Learner服务器之间的连接,其负责Leader和Learner服务器之间几乎所有的消息通信和数据同步。

4.向Leader注册(learner端)

Learner完成和Leader的连接后,会向Leader进行注册,即将Learner服务器的基本信息(LearnerInfo),包括SID和ZXID,发送给Leader服务器。

5.Leader解析Learner信息,计算新的epoch(leader端)

Leader接收到Learner服务器基本信息后,会解析出该Learner的SID和ZXID,然后根据ZXID解析出对应的epoch_of_learner,并和当前Leader服务器的epoch_of_leader进行比较,如果该Learner的epoch_of_learner更大,则更新Leader的epoch_of_leader = epoch_of_learner + 1。然后LearnHandler进行等待,直到过半Learner已经向Leader进行了注册,同时更新了epoch_of_leader后,Leader就可以确定当前集群的epoch了。

6.发送Leader状态。(leader端)

计算出新的epoch后,Leader会将该信息以一个LEADERINFO消息的形式发送给Learner,并等待Learner的响应。

7.Learner发送ACK消息。(learner端)

Learner接收到LEADERINFO后,会解析出epoch和ZXID,然后向Leader反馈一个ACKEPOCH响应。

8.数据同步(leader端)

Leader收到Learner的ACKEPOCH后,即可进行数据同步。

9.启动Leader和Learner服务器。(learner和leader)

当有过半Learner已经完成了数据同步,那么Leader和Learner服务器实例就可以启动了。

源码部分

leader部分在 org.apache.zookeeper.server.quorum.Leader#lead
follower部分在 org.apache.zookeeper.server.quorum.Follower#followLeader

Leader和Follower启动

1. 创建启动会话管理器。
2. 初始化Zookeeper请求处理链,集群模式的每个处理器也会在启动阶段串联请求处理链。
3. 注册JMX服务。

对应的代码在
Learner#syncWithLeader 调用 ZooKeeperServer#startup
Leader#startZkServer 调用 ZooKeeperServer#startup

思考

何时进行leader选举的

QuorumPeer#run中,初始状态是LOOKING
因此调用了

setCurrentVote(makeLEStrategy().lookForLeader());

的逻辑,lookForLeader就根据选举算法产生了leader,具体算法过程之后再讲

选举算法中,目前只支持FastLeaderElection,体现在哪

org.apache.zookeeper.server.quorum.QuorumPeerConfig#electionAlg
值固定为3

然后解析config的时候
org.apache.zookeeper.server.quorum.QuorumPeerMain#runFromConfig
执行

quorumPeer.setElectionType(config.getElectionAlg());

也就是quorumPeer的ElectionAlg是3

然后创建选举算法时
org.apache.zookeeper.server.quorum.QuorumPeer#startLeaderElection
org.apache.zookeeper.server.quorum.QuorumPeer#createElectionAlgorithm
带入的参数也就是3
进入


case 3:FastLeaderElection

问题

leader创立之后怎么知道learner的地址是什么,否则LearnerCnxAcceptor怎么接收所有非Leader服务器的连接请求

没看出来哪里体现,也就是说我可以外部搞一个端口来完成和leader的交互???

refer

http://www.cnblogs.com/leesf456/p/6105276.html
https://my.oschina.net/xianggao/blog/538746
《paxos到zk》

你可能感兴趣的:(zk源码阅读26:集群版服务器启动概述)