RequestProcessor处理请求源码剖析
在上一次分析ZK网络通信源码
的时候我们追溯到了ZookeeperServer.processPacket()
就没有再深入了。
本次就要来介绍具体业务处理的流程。入口为ZookeeperServer.processPacket()
中的submitRequest(si);
概览图:
RequestProcessor结构
概览图:
客户端请求过来,每次执行不同事务操作的时候,Zookeeper也提供了一套业务处理流程RequestProcessor
, RequestProcessor 的处理流程如下图:
我们来看一下 RequestProcessor 初始化流程【在启动zk服务,也就是在zks.startup();
内部进行初始化的】, ZooKeeperServer.setupRequestProcessors()
方法源码如下:
它的创建步骤:
- 创建finalProcessor。
- 创建syncProcessor,并将finalProcessor作为它的下一个业务链。
- 启动syncProcessor。
- 创建firstProcessor(PrepRequestProcessor),将syncProcessor作为firstProcessor的下一个业务链。
- 启动firstProcessor。
syncProcessor
创建时,将finalProcessor
作为参数传递进来源码如下:firstProcessor
创建时,将 syncProcessor
作为参数传递进来源码如下:PrepRequestProcessor
和 SyncRequestProcessor
的结构一样,都是实现了 Thread 的一个线程,所以在这里初始化时便启动了这两个线程。但是FinalRequestProcessor
不是线程。
1、PrepRequestProcessor剖析
PrepRequestProcessor 是请求处理器的第1个处理器,我们把之前的请求业务处理衔接起来,一步一步分析。ZooKeeperServer.processPacket()>submitRequest()>enqueueRequest()>RequestThrottler.submitRequest()
,来看下 RequestThrottler.submitRequest() 源码,它将当前请求添加到submittedRequests
队列中了,源码如下:
看 RequestThrottler
的继承关系就知道它是个线程,我们看看它的 run 方法做了什么事,源码如下:
RequestThrottler 调用了 ZooKeeperServer.submitRequestNow()
方法,而该方法又调用了firstProcessor
的方法,源码如下:
从上段源码可以看出三个RequestProecessor 中最先调用的是PrepRequestProcessor
。PrepRequestProcessor.processRequest()
方法将当前请求添加到了队列 submittedRequests 中,
源码如下:
上面方法中并未从 submittedRequests
队列中获取请求,如何执行请求的呢,因为PrepRequestProcessor
是一个线程,因此会在 run 中执行,我们查看 run 方法源码的时候发现它调用了pRequest()
方法, pRequest() 方法源码如下:
首先先执行pRequestHelper()
方法,该方法是PrepRequestProcessor
处理核心业务流程,主要是一些过滤操作,操作完成后,会将请求交给下一个业务链,也就是SyncRequestProcessor.processRequest()
方法处理请求。
这里可能会好奇pRequestHelper()
具体做了什么,看它的源码会发现做事的其实是pRequest2Txn()
,而pRequest2Txn()
主要做的就是权限校验、快照记录、事务信息记录相关的事,并未涉及到数据处理!!
也就是说 PrepRequestProcessor
其实是做了操作前权限校验、快照记录、事务信息记录相关的事。
2、SyncRequestProcessor剖析
该处理器主要是将请求数据高效率存入磁盘,并且请求在写入磁盘之前是不会被转发到下个处理器的。
我们先看请求被添加到队列的方法:
同样 SyncRequestProcessor
是一个线程,执行队列中的请求也在线程中触发,我们看它的run方法,源码如下:
run 方法会从 queuedRequests
队列中获取一个请求,如果获取不到就会阻塞等待直到获取到一个请求对象,程序才会继续往下执行,接下来会调用 Snapshot Thread
线程实现将客户端发送的数据以快照的方式写入磁盘,最终调用 flush() 方法实现数据提交,flush()
方法源码如下:
flush() 方法实现了数据提交,并且会将请求交给下一个业务链,下一个业务链为FinalRequestProcessor
。
3、FinalRequestProcessor剖析
FinalRequestProcessor
相对前面两个来说没那么复杂,该业务处理对象主要用于返回Response。