会话创建请求
Zookeeper服务端对会话创建的处理,大体可以分为请求接收、会话创建、预处理、事务处理、事务应用和会话响应。
1.请求接收
(1)IO层接收到来自客户端的请求。NIOServerCnxn维护每一个客户端连接,客户端与服务器端的所有通信都是由NIOServerCnxn负责,其负责统一接收来自客户端的所有请求,并将请求内容从底层网络IO中完整地读取出来。
(2)判断是否是客户端会话创建请求。每个会话对应一个NIOServerCnxn实体,对于每个请求,Zookeeper都会检查当前NIOServerCnxn实体是否已经被初始化,如果尚未被初始化,那么就可以确定该客户端一定是会话创建请求。
(3)反序列ConnectRequest请求。
(4)判断是否是ReadOnly客户端。如果当前Zookeeper服务器是以ReadOnly模式启动,那么所有来自非DReadOnly型客户端的请求将无法被处理。因此,服务端需要先检查是否是ReadOnly客户端,并以此决定是否接受该会话创建请求。
(5)检查客户端zxid,正常情况下,在一个Zookeeper集群中,服务端的zxid必定大于客户端的zxid,因此若发现客户端的zxid大于服务端zxid,那么服务端不接受该客户端的会话创建请求。
(6)协商sessionTimeout。
(7)判断是否中需要重新激活创建会话。服务端根据客户端请求中是否包含sessionID来判断该客户端是否面要重新创建会话。
2.会话创建
(1)为客户端生成sessionID。在为客户端创建会话之前,服务端首先会为每个客户端分配一个sessionID.
(2)注册会话。注册会话。向sessionTracker中注册会话,SessionTracker中维护了sessionsWithTimeout和sessionsById。
(3)激活会话。
(4)生成会话密码。
3.预处理
(1)将请求交给PrepRequestProcessor处理器处理。在提交给第一个请求处理器之前,Zookeeper会根据该请求所属的会话,进行一次激活会话操作,以确保当前会话处于激活状态,完成会话激活后,则提交请求至处理器。
(2)创建请求事务头。
(3)创建请求事务体。
(4)处理由非Leader服务器转发过来的会话创建请求。
4.事务处理
(1)将请求交给ProposalRequestProcessor处理器。与提议相关的处理器,从ProposalRequestProcessor开始,请求的处理将会进入三个子处理流程,分别是Sync流程、Proposal流程、Commit流程。
(2)Sync流程
使用SyncRequestProcessor处理器记录事务日志,针对每个事务请求,都会通过事务日志的形式将其记录,完成日志记录后,每个Follower都会向Leader发送ACK消息,表明自身完成了事r务日志的记录,以便Leader统计每个事务请求的投票情况。
(3)Proposal流程
每个事务请求都需要集群中过半机器投票认可才能真正应用到内存数据库中。
- 若当前请是事务请求,在发起事务投票之前,检查当前服务端的ZXID是否可用。
- 若ZXID及可用,Zookeeper会将已创建的请求头和事务体以及ZXID和请求本身序列化到Proposal对象中。
- Leader以ZXID作为标识,将该提议放入投票箱outstandingProposals中,同时将该提议广播给所有Follower。
- Follower接到Leader提议后,进入 Sync流程进行日志记录,记录完成后,发送ACK消息至Leader服务器,Leader根据这些ACK消息来统计每个提议的投票情况,当一个提议获得过半数以上投票,就认为该提议通过,进入commit阶段。
- 将请求放入toBeApplied队列中。
- Leader向Follower和Observer发送commit消息。
(4)Commit流程
- CommitProcessor收到请求后,将其放入queueRequests队列中。
- 单独的线程处理队列中的请求。
- 若取出的是事务请求,把nextPending标记为当前请求。
- 等待Proposal投票。
- 投票通过,该请求会被放入commitedRequests队列中, 同时唤醒commit流程。
- 若commfitedRequests队列中存在可以提交的请求,那么Commit流程则开始提交请交请求,将请求放入toProcess队列中,然后交付下一个请求处器:FinalRequestProcessor。
5.事务应用
(1)FinalRequestProcessor处理器检查outstandingChanges队列中请求的有效性,若发现这些请求已经落后于当前正在处理的请求,那么直接从outstandingChanges队列中移除。
(2)之前的请求处理仅仅将事务记录到事务日志中,而内存数据库中的状态尚未改变,因此,需要将事务变更应用到内存数据库。
(3)完成事务应用后,则将该请求放入commitProposal队列中,commitProposal用来保存最近被提交的事务请求,以便集群机器进行数据的快速同步。
6.会话响应
(1)Zookeeper计算请求在服务端处理所花费的时间,统计客户端连接的基本信息
(2)会话创建成功后的响应,包含了当前客户端和服务端之间的通信协议版本号、会话超时时间、sessionID和会话密码。
(3)序列化ConnectResponse
(4)IO层发送响应给客户端。
SetData请求
1.预处理
(1)IO层接收来自客户端的请求。
(2)判断是否是客户端“会话创建”请求。对于SetData请求,按照正常事务请求进行处理。
(3)将请求交给PrepRequestProcessor处理器进行处理。
(4)创建请求事务头。
(5)会话检查。
(6)反序列化请求,并创建ChangeRecord记录。
(7)ACL检查。
(8)数据版本检查。通过version属性来实现乐观锁机制的写入校验。
(9)创建请求事务体SetDataTxn.
(10)保存事务操作到outstandingChanges队列中。
2.事务处理
对于事务请求,服务端都会发起事务处理流程。所有事务请求都是由ProposalRequestProcessor处理器处理,通过Sync,Proposal, Commit三个子流程相互协作完成。
3.事务应用
(1)交付给FinalRequestProcessor处理器。
(2)事务应用。将请求事务头和事务体直接交给内存数据库ZKDatabase进行事务应用,同时返回ProcessTxnResult对象,包含了数据节点内容更新后stat。
(3)将事务请求放入commintProposal队列。
4.请求响应
(1)创建响应体SetDataResponse。其包含了当前数据节点的最新状态stat。
(2)创建响应头,包含当前响应对应的事务ZXID和请求处理是否成功的标识。
(3)序列化响应。
(4)IO层发送响应给客户端。
GetData请求
1.预处理
(1)IO层接收来自客户端的请求。
(2)判断是否是客户端“会话创建”请求。
(3)将请求交给PreRequestProcessor处理器进行处理。
(4)会话检查。
2.非事务处理
(1)反序列化GetDataRequest请求。
(2)获取数据节点。
(3)ACL检查。
(4)获取数据内容和stat,注册Watcher。
3.请求响应
(1)创建响应体GetDataResponse。响应体包含当前数据节点的内容和状态stat。
(2)创建响应头。
(3)统计处理。
(4)序列化响应
(5)IO层发送响应给客户端。
最后欢迎大家访问我的个人网站:1024s