zk server处理命令涉及到3个类,2个线程:一个命令请求先后经过PrepRequestProcessor,SyncRequestProcessor,FinalRequestProcessor。

PrepRequestProcessor类对应线程ProcessThread,SyncRequestProcessor类对应线程SyncThread。

在命令到达PrepRequestProcessor之前,还有一段路程:

//ZooKeeperServer
public void processPacket(ServerCnxn cnxn, ByteBuffer incomingBuffer) throws IOException {
// We have the request, now process and setup for next
InputStream bais = new ByteBufferInputStream(incomingBuffer);
BinaryInputArchive bia = BinaryInputArchive.getArchive(bais);
RequestHeader h = new RequestHeader();
h.deserialize(bia, "header");
// Through the magic of byte buffers, txn will not be
// pointing
// to the start of the txn
incomingBuffer = incomingBuffer.slice();
if (h.getType() == OpCode.auth) {
...
return;
} else {
if (h.getType() == OpCode.sasl) {
Record rsp = processSasl(incomingBuffer,cnxn);
ReplyHeader rh = new ReplyHeader(h.getXid(), 0, KeeperException.Code.OK.intValue());
cnxn.sendResponse(rh,rsp, "response"); // not sure about 3rd arg..what is it?
}
else { //默认走这个分支
Request si = new Request(cnxn, cnxn.getSessionId(), h.getXid(),
h.getType(), incomingBuffer, cnxn.getAuthInfo());
si.setOwner(ServerCnxn.me);
submitRequest(si);
}
}
cnxn.incrOutstandingRequests(h);
} public void submitRequest(Request si) {
//省略其他代码
touch(si.cnxn);
boolean validpacket = Request.isValid(si.type);
if (validpacket) {
firstProcessor.processRequest(si);
if (si.cnxn != null) {
incInProcess();
}
} else {
LOG.warn("Received packet at server of unknown type " + si.type);
new UnimplementedRequestProcessor().processRequest(si);
}
}

进firstProcessor

//PrepRequestProcessor类片段
public class PrepRequestProcessor extends Thread implements RequestProcessor {
LinkedBlockingQueue<Request> submittedRequests = new LinkedBlockingQueue<Request>();
RequestProcessor nextProcessor; public void processRequest(Request request) {
//这个方法只是把请求加入到阻塞队列中
submittedRequests.add(request);
} @Override
public void run() {
try {
while (true) {
//从队列中取出请求
Request request = submittedRequests.take();
long traceMask = ZooTrace.CLIENT_REQUEST_TRACE_MASK;
if (request.type == OpCode.ping) {
traceMask = ZooTrace.CLIENT_PING_TRACE_MASK;
}
if (LOG.isTraceEnabled()) {
ZooTrace.logRequest(LOG, traceMask, 'P', request, "");
}
if (Request.requestOfDeath == request) {
break;
}
//处理请求,给写请求设置hdr,读请求的hdr为null
pRequest(request);
}
} catch (InterruptedException e) {
LOG.error("Unexpected interruption", e);
} catch (RequestProcessorException e) {
if (e.getCause() instanceof XidRolloverException) {
LOG.info(e.getCause().getMessage());
}
LOG.error("Unexpected exception", e);
} catch (Exception e) {
LOG.error("Unexpected exception", e);
}
LOG.info("PrepRequestProcessor exited loop!");
}
protected void pRequest(Request request) throws RequestProcessorException {
//代码较长,只抓重要逻辑
request.hdr = null;
request.txn = null;
……
request.zxid = zks.getZxid();
//这个nextProcessor为SyncRequestProcessor,这个时候请求就到了SyncRequestProcessor的队列中了
nextProcessor.processRequest(request);
}
}

进入SyncRequestProcessor后:

//SyncRequestProcessor代码片段
public class SyncRequestProcessor extends Thread implements RequestProcessor {
private final LinkedBlockingQueue<Request> queuedRequests = new LinkedBlockingQueue<Request>();
private final RequestProcessor nextProcessor; public void processRequest(Request request) {
// request.addRQRec(">sync");
queuedRequests.add(request);
} //猜个大致原则吧
//优先处理queuedRequests中的请求
//处理写请求,先写log日志,然后存入toFlush列表
//当queuedRequests中没有数据时,处理toFlush列表
//或者toFlush.size() > 1000时,处理toFlush列表
@Override
public void run() {
try {
int logCount = 0; // we do this in an attempt to ensure that not all of the servers
// in the ensemble take a snapshot at the same time
setRandRoll(r.nextInt(snapCount/2));
while (true) {
Request si = null;
if (toFlush.isEmpty()) {
si = queuedRequests.take();
} else {
si = queuedRequests.poll();
if (si == null) {
flush(toFlush);
continue;
}
}
if (si == requestOfDeath) {
break;
}
if (si != null) {
// track the number of records written to the log
// zks.getZKDatabase().append(si) 对于写请求,改调用返回true,读请求返回false
// 写请求有hdr,读请求hdr为null
if (zks.getZKDatabase().append(si)) {
logCount++;
if (logCount > (snapCount / 2 + randRoll)) {
randRoll = r.nextInt(snapCount/2);
// roll the log
zks.getZKDatabase().rollLog();
// take a snapshot
if (snapInProcess != null && snapInProcess.isAlive()) {
LOG.warn("Too busy to snap, skipping");
} else {
snapInProcess = new Thread("Snapshot Thread") {
public void run() {
try {
zks.takeSnapshot();
} catch(Exception e) {
LOG.warn("Unexpected exception", e);
}
}
};
snapInProcess.start();
}
logCount = 0;
}
} else if (toFlush.isEmpty()) {
//toFlush列表为空时,读请求进入该分支
// optimization for read heavy workloads
// iff this is a read, and there are no pending
// flushes (writes), then just pass this to the next
// processor
if (nextProcessor != null) {
nextProcessor.processRequest(si);
if (nextProcessor instanceof Flushable) {
((Flushable)nextProcessor).flush();
}
}
continue;
}
toFlush.add(si);
if (toFlush.size() > 1000) {
flush(toFlush);
}
}
}
} catch (Throwable t) {
LOG.error("Severe unrecoverable error, exiting", t);
running = false;
System.exit(11);
}
LOG.info("SyncRequestProcessor exited!");
}
}

zookeeper server处理客户端命令的流程的更多相关文章

  1. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  2. zookeeper客户端命令详解

    今天同事突然向看一下zookeeper中都创建了哪些节点,而我本人对zookeeper的客服端命令了解的很少,有些操作竟然不知道怎么用,于是乎就索性整理一下zookeeper客服端命令的使用,并再此记 ...

  3. 五:ZooKeeper的集群命令客户端的链接和命令操作的使用

    一:zookeeper客户端链接[1]进入zookeeper的安装目录的bin目录下         # cd /opt/zookeeper/bin[2]敲击链接客户端的命令(zkCli.sh)    ...

  4. Linux系统下zookeeper客户端命令使用

    1. 启动客户端 [admin@yrjk bin]$ ./zkCli.sh [zk: localhost:2181(CONNECTED) 0] 2. 显示所有操作命令 [zk: localhost:2 ...

  5. ZooKeeper学习笔记(四)——shell客户端命令操作

    ZooKeeper客户端命令行操作 启动服务端 [simon@hadoop102 zookeeper-3.4.10]$ bin/zkServer.sh start 查看状态信息 Using confi ...

  6. coTurn 运行在Windows平台的方法及服务与客户端运行交互流程和原理

    coTurn是一个开源的STUN和TURN及ICE服务项目,只是不支持Windows.为了在window平台上使用coTurn源码,需要在windows平台下安装Cygwin环境,并编译coTurn源 ...

  7. zookeeper之 zkServer.sh命令、zkCli.sh命令、四字命令

    一.zkServer.sh 1.查看 zkServer.sh 帮助信息[root@bigdata05 bin]# ./zkServer.sh helpZooKeeper JMX enabled by ...

  8. 搭建zookeeper单机版以及简单命令的使用

    1:创建目录 #数据目录dataDir=/opt/hadoop/zookeeper-3.3.5-cdh3u5/data#日志目录dataLogDir=/opt/hadoop/zookeeper-3.3 ...

  9. Zookeeper的结构和命令

    1. Zookeeper的特性 1.Zookeeper:一个leader,多个follower组成的集群. 2.全局数据一致:每个server保存一份相同的数据副本,client无论连接到哪个serv ...

随机推荐

  1. Linux系统的vi命令

    Linux系统的vi命令 vi编辑命令 1,格式: #vi filename 2,用法: //打开或新建文件,并将光标置于第一行首 #vi + filename //打开文件,并将光标置于第n行首 # ...

  2. 20145324王嘉澜《网络对抗技术》Web基础

    实践要求 ①Web前端HTML: 能正常安装.启停Apache.理解HTML,理解表单,理解GET与POST方法,编写一个含有表单的HTML ②Web前端javascipt: 理解JavaScript ...

  3. TableView,自定义TableViewCell

    自定义Table 原理: http://blog.jobbole.com/67272/ http://www.cnblogs.com/wangxiaofeinin/p/3532831.html 补充: ...

  4. JavaScript:正则表达式 问号

    问号 1.?表示重复前面内容的0次或一次(但尽可能多重复) var reg=/abc?/g; var str="abcdabcaba"; console.log(str.match ...

  5. 【转载】Multiboot规范

    转自:Multiboot规范 Multiboot规范 本文定义了Multiboot规范--提议中的引导过程标准.本文是此规范的0.6.93版. Multiboot规范简介 本章描述了一些关于Multi ...

  6. NS3 使用NS3工具PyViz

    官方文档 跑了一个样例(first.py): 由于 NetAnim 对我实在是有点不友好,在 PyViz 和 NetAnim 之间,我倾向前者.后者需要生成.xml文件,相比前者较为麻烦. 安装过程: ...

  7. axios post请求报错

    问题描述: vue中使用axios提交post请求, 请求地址及参数都对, 但是一直报缺少参数的错误 探索:对比post请求数据, 提交数据的方式不对 (1)axios的post请求(返回响应缺少参数 ...

  8. Cocos2d-x学习笔记(十)CC_CALLBACK回调函数相关宏

    这里加入一个插曲,是关于Cocos2d-x回调函数的.首先,让我们Cocos支持的回调函数宏有哪些,以及其原型: // new callbacks based on C++11 #define CC_ ...

  9. Python代码规范与命名规则

    1.模块 模块尽量使用小写命名,首字母保持小写,尽量不要用下划线(除非多个单词,且数量不多的情况) # 正确的模块名 import decoder import html_parser # 不推荐的模 ...

  10. VC6的VCVARS32.BAT所在位置

    1. C:\Program Files (x86)\Microsoft Visual Studio\VC98\Bin\VCVARS32.BAT 2.