摘要
本节结合源码对集群版服务器启动进行概述,流程图如下
主要分为
预启动
初始化
Leader选举(选举算法在之后讲)
Leader和Follower启动期交互过程
Leader和Follower启动
这里都是概述,没有详细分析源码,下面几节展开分析
预启动
1. 统一由QuorumPeerMain作为启动类。
2. 解析配置文件zoo.cfg。
3. 创建并启动历史文件清理器DatadirCleanupFactory。
4. 判断当前是集群模式还是单机模式的启动。
在集群模式中,在zoo.cfg文件中配置了多个服务器地址,可以选择集群启动。
上述代码都在org.apache.zookeeper.server.quorum.QuorumPeerMain#initializeAndRun中,截图如下
初始化
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中,顺序不完全一样
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
上述步骤在
2-4的源码步骤太长了,这里不贴出来了,就在QuorumPeer#run中
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
进入
问题
leader创立之后怎么知道learner的地址是什么,否则LearnerCnxAcceptor怎么接收所有非Leader服务器的连接请求
没看出来哪里体现,也就是说我可以外部搞一个端口来完成和leader的交互???
refer
http://www.cnblogs.com/leesf456/p/6105276.html
https://my.oschina.net/xianggao/blog/538746
《paxos到zk》