最近又开启了一个新项目,时间比较紧,博客写的速度也比较慢,可是仍是不能放松要求~但愿最近周末能抽点时间把上周漏掉的博客补上~java
在前一篇大体描述了单机server的启动过程后,从这一篇开始咱们将开始集群server的一些机制的一些了解,主要还有servr的启动,处理链,选举等等大的模块须要完善。算法
其实从大体的流程上来讲,单机server和集群server的处理是基本一致的,都是会从主函数启动而后去初始化一些zookeeper运行必须的一些功能类,而最大的不一样点也就在于集群server是分布式的,多了一个选举的过程,这个选举的过程本篇不会深刻去讲,应该会分为两篇,一篇讲Zookeeper选举依赖的ZAB算法,另外一篇主要说下具体的流程。数据库
首先经过流程图看下集群server的启动过程:分布式
从图中也能够看到,确实和上一篇所说的单机server的启动流程大体一致。ide
总的来讲,和单机server的启动过程相比,除了预启动和初始化两个状态以外,还有一个leader选举的过程。函数
与单机server启动过程同样,集群server启动一样以QuorumPeerMain类做为启动类;ui
解析zoo.cfg;this
建立并启动历史文件清理器DatadirCleanupManager;spa
判断启动模式。线程
if (args.length == 1 && config.servers.size() > 0) { runFromConfig(config); }
能够看到,在集群模式下(zoo.cfg中配置了多个server),zk会直接开始以集群模式启动server。这部分的启动顺序和单机版的是基本一致的,它们都是共用的同一份代码。
在预启动以后即是初始化的过程。
public void runFromConfig(QuorumPeerConfig config) throws IOException { try { ManagedUtil.registerLog4jMBeans();//注册log的bean } catch (JMException e) { LOG.warn("Unable to register log4j JMX control", e); } LOG.info("Starting quorum peer"); try { ServerCnxnFactory cnxnFactory = ServerCnxnFactory.createFactory();//建立ServerCnxnFactory cnxnFactory.configure(config.getClientPortAddress(),//初始化ServerCnxnFactory config.getMaxClientCnxns()); //建立并初始化QuorumPeer quorumPeer = getQuorumPeer(); //初始化的数据基本都是从zoo.cfg中读到的值,方法名也叫runFromConfig quorumPeer.setQuorumPeers(config.getServers()); quorumPeer.setTxnFactory(new FileTxnSnapLog(//建立数据管理器FileTxnSnapLog new File(config.getDataLogDir()), new File(config.getDataDir()))); quorumPeer.setElectionType(config.getElectionAlg()); quorumPeer.setMyid(config.getServerId()); quorumPeer.setTickTime(config.getTickTime()); quorumPeer.setInitLimit(config.getInitLimit()); quorumPeer.setSyncLimit(config.getSyncLimit()); quorumPeer.setQuorumListenOnAllIPs(config.getQuorumListenOnAllIPs()); quorumPeer.setCnxnFactory(cnxnFactory); quorumPeer.setQuorumVerifier(config.getQuorumVerifier()); quorumPeer.setClientPortAddress(config.getClientPortAddress()); quorumPeer.setMinSessionTimeout(config.getMinSessionTimeout()); quorumPeer.setMaxSessionTimeout(config.getMaxSessionTimeout()); quorumPeer.setZKDatabase(new ZKDatabase(quorumPeer.getTxnFactory())); quorumPeer.setLearnerType(config.getPeerType()); quorumPeer.setSyncEnabled(config.getSyncEnabled()); // sets quorum sasl authentication configurations quorumPeer.setQuorumSaslEnabled(config.quorumEnableSasl); if(quorumPeer.isQuorumSaslAuthEnabled()){ quorumPeer.setQuorumServerSaslRequired(config.quorumServerRequireSasl); quorumPeer.setQuorumLearnerSaslRequired(config.quorumLearnerRequireSasl); quorumPeer.setQuorumServicePrincipal(config.quorumServicePrincipal); quorumPeer.setQuorumServerLoginContext(config.quorumServerLoginContext); quorumPeer.setQuorumLearnerLoginContext(config.quorumLearnerLoginContext); } quorumPeer.setQuorumCnxnThreadsSize(config.quorumCnxnThreadsSize); quorumPeer.initialize(); quorumPeer.start(); quorumPeer.join(); } catch (InterruptedException e) { // warn, but generally this is ok LOG.warn("Quorum Peer interrupted", e); } }
经过上面的代码及注释能够看出,初始化过程分为下面几步:
3,4两步都是在quorumPeer.start();中完成的,特别要注意的是,QuorumPeer重写了thread类的start方法,因此这里调用了start方法并非直接去调用QuorumPeer的run方法,而真正调用QuorumPeer的run方法是在QuorumPeer的start方法中super.start()这一步。
@Override public synchronized void start() { loadDataBase();//恢复本地数据 cnxnFactory.start();//启动ServerCnxnFactory线程 startLeaderElection();//启动leader选举 super.start();//启动QuorumPeer线程,并在 }
这里能够看到,在start的过程当中,会有一步是作leader的选举的,而这也是集群和单机server启动时最大的区别,这一步将在下篇博客中专门讲一下。
而至于super.start(),这部分主要干了两个是:
这两部在下篇也会详细说。
单机和集群server启动中,除了集群server启动多了一个leader选举过程外,还有个区别是单机server会读两遍zoo.cfg,其实为何不在ZookeeperMain里“重载”main方法(写个流程差很少的方法),以QuorumPeerConfig做为参数,这样就不用读第二遍了。不过估计是由于读配置工做量比较小,因此没有作这个事。
从paxos到zk