背景
Zookeeper中使用责任链模式处理客户端提交的请求,本文介绍常用的RequestProcessor如何工作?各线程间如何通信?
注:下文中使用事务代表会改变服务器状态的请求,如创建节点,更新数据
单机版初始化
单机版服务器在初始化ZooKeeperServer时,创建并启动了请求处理链,代码如下:
/**
* 设置单机版服务器的请求处理链
* {@link PrepRequestProcessor}->{@link SyncRequestProcessor}->{@link FinalRequestProcessor}
*/
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();
}
单机版服务器包含3个请求处理器,从前往后依次为PrepRequestProcessor->SyncRequestProcessor->FinalRequestProcessor
PrepRequestProcessor
基本功能
PrepRP是服务器的请求预处理器,能够识别出当前客户端是否是事务请求,对于事务请求,PrepRP对其进行一系列预处理,如创建请求事务头,事务体,会话检查,ACL检查等.
由于其检查请求是否是事务请求,因此其代码中存在大量的switch... case ...,代码重复且庞杂,因此就不贴源码了.
线程通信
PrepRP继承了Thread,因此其是一个单独的线程,通过PrepRP.submittedRequests与其他线程通信,submittedRequests中存放待处理的请求,调用processRequest()即可将request添加至submittedRequests中:
@Override
public void processRequest(Request request) {
submittedRequests.add(request);
}
我们来逆向推下该方法的调用链:
PrepRequestProcessor.processRequest()<-ZooKeeperServer.submitRequest()<-ZooKeeperServer.processPacket()<-NIOServerCnxn.readRequest()<-NIOServerCnxn.readPayload()<-NIOServerCnxn.doIO()
不知道你对最后一个方法NIOServerCnxn.doIO()是否有印象,该方法在worker thread中被调用,用于读取客户端发送的数据,因此submittedRequests就是worker thread和prepRP thread通信的工具.
SyncRequestProcessor
基本功能
SyncRP的主要功能就是生成快照文件和将事务写入事务日志中.详见Zookeeper-持久化
线程通信
SyncRP也继承了Thread,通过queuedRequests与prepRP thread通信,调用processRequest()即可将request添加至queuedRequests中:
/**
* @param request 将要被处理的request
*/
@Override
public void processRequest(Request request) {
//将request加入请求队列
queuedRequests.add(request);
}
FinalRequestProcessor
基本功能
FinalRP主要完成两个功能:
- 创建客户端请求的响应
- 将事务应用到内存数据中去
代码较为简单,就不贴源码了.
本文介绍了Zookeeper单机版服务器的请求处理链:PrepRequestProcessor负责预处理客户端请求;SyncRequestProcessor负责生成快照文件及事务日志;FinalRequestProcessor负责创建客户端请求的响应并将事务应用到内存数据中。

1969

被折叠的 条评论
为什么被折叠?



