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. Mysql优化_内置profiling性能分析工具

    如果要进行SQL的调优优化和排查,第一步是先让故障重现,但是这个并不是这一分钟有问题,下一秒就OK.一般的企业一般是DBA数据库工程师从监控里找到问题.DBA会告诉我们让我们来排查问题,那么可能很多种 ...

  2. bzoj1660 / P2866 [USACO06NOV]糟糕的一天Bad Hair Day

    P2866 [USACO06NOV]糟糕的一天Bad Hair Day 奶牛题里好多单调栈..... 维护一个单调递减栈,存每只牛的高度和位置,顺便统计一下答案. #include<iostre ...

  3. 01: requests模块

    目录: 1.1 requests模块简介 1.2 使用requests模块发送get请求 1.3 使用requests模块发送post请求 1.4 requests.request()参数介绍 1.1 ...

  4. 20145317彭垚 MSF基础应用

    20145317彭垚 MSF基础应用 基础问题回答 用自己的话解释什么是exploit,payload,encode? exploit就相当于是载具,将真正要负责攻击的代码传送到靶机中,我觉得老师上课 ...

  5. MBR主引导扇区解析2

    unsigned AnsiChar data[] = { 0x33, 0xC0, 0x8E, 0xD0, 0xBC, 0x00, 0x7C, 0x8E, 0xC0, 0x8E, 0xD8, 0xBE, ...

  6. JavaScript 各种验证收集

    filter或者forEach函数,可能是因为你的浏览器还不够新,暂时不支持新标准的函数,你可以使用如下方式自己定义: if (!Array.prototype.forEach) { Array.pr ...

  7. 【第十三章】 springboot + lombok

    lombok作用:消除模板代码. getter.setter.构造器.toString().equals() 便捷的生成比较复杂的代码,例如一个POJO要转化成构建器模式的形式,只需要一个注解. 注意 ...

  8. zeptojs库解读2之事件模块

    第一,通过obj.addEventListener("click",fn)绑定的事件,你不能通过obj.onclick = null;来移除绑定点击事件的所有回调函数. 所以引入第 ...

  9. Cocos2d-x学习笔记(七)菜单

    菜单类继承关系如下: 图1 菜单类继承关系 文本菜单只能显示文本,包括:MenuItemLabel.MenuItemFont和MenuItemAtlasFont: #include "Hel ...

  10. 关于QT的QPainterPath::arcTo 详解

    这个函数文档的意思就是画弧,看了文档也不太明白,自己做了demo终于明白了意思 移动到圆心,画180度半圆 void TestArcTo::paintEvent(QPaintEvent *) { QP ...