zookeeper(5)—— zk服务端单机源码

我们在win下启动是从D:\tools\zookeeper\zookeeper-3.4.14\bin下的zkServer.cmd,打开这个脚本,可以看到其实就是运行org.apache.zookeeper.server.quorum.QuorumPeerMain这个类,先看这个类的main方法

81 main.initializeAndRun(args);
=>114 runFromConfig(config);  //如果配置了集群,解析集群相关信息
=>119 ZooKeeperServerMain.main(args);  //单机版服务器,本次主要看这个方法

这个main方法中,分为两个分支,我们主要看ZooKeeperServerMain.main(args);

55 main.initializeAndRun(args);
=>75-87 创建一个配置对象config用于保存配置信息
=>89 runFromConfig(config);

服务端启动,先读取配置文件,保存到内存中,然后执行runFromConfig(config);跟进

105-117 new ZooKeeperServer();  //创建zk服务端,并设置其参数
118 cnxnFactory = ServerCnxnFactory.createFactory();  //创建访问协议,默认NIO
119 cnxnFactory.configure方法 //创建zookeeperThread,并启动一个socket等待客户端的连接
121 cnxnFactory.startup(zkServer);

先创建ZookeeperServer对象,再创建cnxnFactory对象(默认NIO,也可以通过配置文件使用Netty)

调用cnxnFactory.configure方法时,会创建zookeeperThread,并启动一个socket等待客户端的连接

最后通过cnxnFactory.startup(zkServer); 跟进这个会提示有两个子类,我们选择默认方式NIOServerCnxnFactory

116 start();  //启动了本类的run方法
117 setZooKeeperServer(zks);
118 zks.startdata();
119 zks.startup();

分别来看这四个方法

1) start();  

作用:启动了本类(NIOServerCnxnFactory)的run方法,这个run方法一直在while循环判断socket是否关闭,没有的话则

=>226 c.doIO(k);  //当监听到客户端发来的读或写的请求
==>245 if (k.isReadable())  //如果是读请求
==>246 sock.read(incomingBuffer); //从socket读取数据到incomingBuffer
==>264 readPayload(); //先判断是否初始化过,初始化过的话就读请求
===>393 zkServer.processPacket(this, incomingBuffer);
====>1023 submitRequest(si);
=====>750 firstProcessor.processRequest(si); //PrepRequestProcessor这个类的processRequest,最终将读请求放到submittedRequest这个队列里
==>273 if (k.isWritable())  //如果是写请求
==>273-364 把写请求放入outgoingBuffers

也就是说,通过NIOServerCnxnFactory的run方法,服务端对客户端的请求进行监听,当有请求时,根据读、写请求分别进行处理

2) setZooKeeperServer(zks);//没什么好说的,只是设置一下

3) zks.startdata();//加载日志和快照

4) zks.startup();

=>410 进入ZooKeeperServer的startup
=>414 startSessionTracker();//查看session是否超时,别的没做什么
=>415 setupRequestProcessors();//重点

其中415行,是重点,代码如下

    protected void setupRequestProcessors() {
        RequestProcessor finalProcessor = new FinalRequestProcessor(this);
        RequestProcessor syncProcessor = new SyncRequestProcessor(this,finalProcessor);
        ((SyncRequestProcessor)syncProcessor).start();
        firstProcessor = new PrepRequestProcessor(this, syncProcessor);
        ((PrepRequestProcessor)firstProcessor).start();
    }

创建了三个对象PrepRequestProcessorSyncRequestProcessorFinalRequestProcessor,通过链式调用,我们按照调用顺序分别看下这三个对象的作用:

首先、调用PrepRequestProcessor的run方法(真正处理客户端请求

123 submittedRequests.take();//获取一个请求
134 pRequest(request);//处理客户端的请求
=>540 pRequest2Txn(request.type, zks.getNextZxid(), request, createRequest, true);//根据操作类型,进行相应的处理
==>375 addChangeRecord(parentRecord); //处理完成后,将处理逻辑加入outstandingChanges队列
至此PrepRequestProcessor的run方法已看完,主要是处理客户端的请求,然后将处理结果加入到outstandingChanges队列

其次、再看SyncRequestProcessor的run方法(记录内存,及快照

127 si = queuedRequests.take();//获取一个请求
140-160 记录日志,如果超过配置的参数snapCount / 2 + randRoll则记录快照
169 nextProcessor.processRequest(si); //进入FinalRequestProcessor

最后、再看FinalRequestProcessor.processRequest(si)

117 rc = zks.processTxn(hdr, txn);
=>1075 rc = getZKDatabase().processTxn(hdr, txn); //zk的内存数据库,将请求保存的内存(客户端请求处理完后,日志,快照(超过),内存都有)
==>700-760 根据不同请求类型,操作内存数据库
==>807 ProcessTxnResult subRc = processTxn(subHdr, record); //开始响应客户端

至此,单机版服务器结束

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值