ZooKeeper集群中的跟随者对客户端请求的处理流程解读(二)
前篇简要回顾:在ZooKeeper集群选举完成之后,各个集群节点各就各位,领导者开始领导、跟随者开始跟随,我们已经看到跟随者建立和领导者的连接,并接受领导者的命令开始恢复,恢复完成之后领导者给了跟随者一个UPTODATE命令,跟随者开始进入接客状态。。。
那么这里出现了两条线,跟随者一方面开始接客(接收并处理客户端的读写请求,为ZK客户端服务),另一方面跟随者保持和领导者的密切连接,通过连接做一些事情,这个会在后面讲到,我们先看看跟随者是如何接客的,这也是和文章的标题相呼应。
跟随者为客户端服务的入口在这里我们通过NettyServerCnxnFactory这个类介绍,这个类是ZK通过Netty(NIO框架)来处理网络层业务的实现,我的之前一篇文章(http://jvmplus.duapp.com /blog/view/B143299758)有介绍Netty在ZooKeeper中的应用,其中介绍了NettyServerCnxnFactory 是如何基于Netty建立网络连接、获取连接通道、接收和发送网络数据的,关于这部分读者可以直接简要阅读下那篇文章,这里我么你直接往下走,看ZK是如 何和客户端进行互动的。
看下NettyServerCnxnFactory的 processMessage方法,这个方法主要是用来处理通道数据的,这里ZK对客户端的连接通道主要消息类型有两种,分别是 ResumeMessageEvent(回复通道事件)和Netty从通道拿到数据并封装的原始类型,即非ResumeMessageEvent类型。 ResumeMessageEvent类型消息是ZK通过实现Netty的MessageEvent接口实现的一种消息事件类型,主要是用来区别是原始网 络通道读取的客户端消息事件,还是ZK通过Netty的ChannelPipeline类的sendUpstream方法向通道上传的消息事件类型数据, 后面processMessage方法会针对这两种不同类型的消息事件类型做不同的事情。
当从通道中读取ResumeMessageEvent类型的消息事件类型的时候,ZK做的事情主要是回复通道,将通道设置为可读(OP_READ)模式。
这里主要是看下ZK对非 ResumeMessageEvent类型的消息事件类型的处理,ZK为了防止通道的数据量太大,发生拥堵现象,ZK给 NettyServerCnxn(代表ZK和客户端连接的抽象)设置了一个字段throttled,它用来标识当前通道的数据是不是可以直接拿来处理,也 就是当处理的速度跟不上IO的速度额度时候,ZK会将throttled这个值设置为true,如果是throttled状态,则ZK将读取的消息放入内 存等待处理队列里面;如果当前通道处于非throttled状态,ZK首先看看等待队列是不是有数据在等待,如果有,ZK将读取的数据写入等待队列里面, 然后开始处理队列数据。如果队列为空,则ZK直接处理通道的数据,然后看看是否还有剩余,如果通道有剩余数据则将剩余数据写入等待队列。下面用图简单表示 一下ZK在这里对客户端端口网络消息的处理流程:
接 下来就是NettyServerCnxn的receiveMessage方法是如何对通道拿到的消息进行处理的,ZK这里会首先判断是否有可读消息,并且 再次判断throttled的状态,如果不满足可读的条件则关闭和客户端的连接,通常正常状态的ZK和客户端的连接应该是长连接,这里为什么为断开?这里 应该是发生了异常,也就是通道接收到了消息事件,但是又是不可读,则ZK会关闭和客户端的连接。
这 里ZK会判断连接的状态,如果是未初始化状态则ZK会把这个请求是当做连接请求,否则会会交给processPacket来处理。 processPacket会首先解析客户端请求包的类型,包括auth、sasl和普通类型三种,前两种类型是认证和授权相关的,后面有机会再介绍,这 里主要介绍普通类型包的处理过程,于是到了ZooKeeperServer的submitRequest这个方法,总算快要开始ZK对客户端请求处理流程 的核心部分了。
下篇文章进入ZooKeeper对客户端请求处理流程的核心部分。