ZooKeeper之Session

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/carson0408/article/details/84193056

        会话是ZooKeeper中最重要的概念之一,客户端与服务端之间的交互操作就是依赖于ZooKeeper的会话机制。接下来分别从客户端与服务端两方面来讲解会话的创建流程与实现细节。

1.创建会话客户端流程

        客户端分为初始化阶段、会话创建阶段和响应处理阶段。

初始化阶段

1.初始化ZooKeeper对象:通过实例化一个ZooKeeper对象,在初始化过程中,创建一个客户端Watcher管理器:ClientWatchManager。

2.设置会话默认Watcher:如果在构造方法中传入了一个Watcher对象,那么客户端会将这个对象作为默认Watcher保存在ClientWatcheManager。

3.构造ZooKeeper服务器地址列表管理器:对于构造方法传入的服务器地址,客户端会将其放在地址列表管理器HostProvider中。

4.创建并初始化客户端网络连接器:ZooKeeper客户端首先会创建一个网络连接器ClientCnxn,用来管理客户端与服务器的网络交互,同时创建了ClientCnxn连接器的底层I/O处理器ClientCnxnSocket。另外,还会初始化客户端两个核心队列outgoingQueue和pendingQueue,分别作为客户端的请求发送队列和服务端响应的等待队列。

5.初始化SendThread和EventThread:SentThread和EventThread是ClientCnxn的两个内部类,也是客户端的两个核心线程,前者用于管理客户端和服务端之间的所有网络I/O,后者则用于进行客户端的事件处理。同时,客户端还会将ClientCnxnSocket分配给SendThread作为底层网络I/O处理器,并初始化EventThread的待处理事件队列waitingEvents,用于存放所有等待被客户端处理的事件。

会话创建阶段

6.启动SendThread和EventThread:SendThread首先会判断当前客户端的状态,进行一系列请理性工作,为客户端发送"会话创建"请求做准备。

7.获取一个服务器地址:在开始创建TCP连接之前,SendThread首先会从HostProvider中随机获取出一个地址,然后委托给ClientCnxnSocket去创建与ZooKeeper服务器之间的TCP连接。

扫描二维码关注公众号,回复: 4158351 查看本文章

8.创建TCP连接:获取到一个服务器地址后,ClientCnxnSocket负责和服务器创建一个TCP长连接。

9.构造ConnectRequest请求:SendThread会负责根据当前客户端的实际设置,构造出一个ConnectRequest请求,该请求代表客户端试图与服务端创建一个会话。同时,ZooKeeper客户端还会进一步将该请求包装成网络I/O层的Packet对象,放入请求发送队列outgoingQueue中去。

10.发送请求:ClientCnxnSocket负责从outgoingQueue中取出一个待发送的Packet对象,将其序列化成ByteBuffer后,向服务端进行发送。

响应处理阶段

11.接收服务端响应:ClientCnxnSocket接收到服务端的响应后,会首先判断当前的客户端状态是否是"已初始化",如果尚未完成初始化,那么就认为该响应一定是会话创建请求的响应,直接交由readConnectResult方法来处理该响应。

12.处理Response:ClientCnxnSocket会对接收到的服务端响应进行反序列化,得到ConnectResponse对象,并从中获取到ZooKeeper服务端分配的会话sessionId。

13.连接成功:一方面需要通知SendThread线程,进一步对客户端进行会话参数的设置,包括readTimeout和connectTimeout等,并更新客户端状态;另一方面,需要通知地址管理器HostProvider当前成功连接的服务器地址。

14.生成事件SyncConnected-None:为了能够让上层应用感知到会话的成功创建,SendThread会生成一个SyncConnected-None,代表客户端与服务器会话创建成功,并将该时间传递给EventThread线程。

15.查询Watcher:EventThread线程接收到事件后,会从ClientWatchManager管理器中查询出对应的Watcher,针对SyncConnected-None事件,那么就直接找出步骤2中存储的默认Watcher,然后将其放到EventThread中的waitingEvents队列中,

16.处理事件:EventThread不断地从waitingEvents队列中取出待处理的Watcher对象,然后直接调用该对象的process接口方法。

2.会话创建服务端流程

请求接收

1.I/O层接收来自客户端的请求:ZooKeeper中,NIOServerCnxn实例维护每一个客户端连接,其负责统一接收来自客户端的所有请求,并将请求内容从底层网络I/O中完整地读取出来。

2.判断是否是客户端"会话创建"请求:如果尚未被初始化,那么就可以确定该客户端请求一定是"会话创建"请求。

3.反序列化ConnectRequest请求:一旦确定当前客户端请求是“会话创建”请求,那么服务端就可以对其进行反序列化,并生成一个ConnectRequest请求实体。

4.判断是否是ReadOnly客户端:在ZooKeeper的设计实现中,如果当前ZooKeeper服务器是以ReadOnly模式启动的,那么所有来自非ReadOnly型客户端的请求将无法被处理。

5.检查客户端ZXID:正常情况下,同一个ZooKeeper集群中,服务端的ZXID值必定大于客户端的ZXID。

6.协商sessionTimeout:客户端向服务器发送这个超时时间后,服务器会根据自己的超时时间限制最终确定该会话的超时时间。

7.判断是否需要重新创建会话:服务端根据客户端请求中是否包含sessionID来判断该客户端是否需要重新创建会话。如果客户端请求中包含了SessionID,那么就认为该客户端正在进行会话重连,只需要重新打开这个会话即可,否则需要重新创建。

会话创建

8.为客户端生成sessionID:在为客户端创建会话之前,服务端首先会为每个客户端都分配一个sessionID.

9.注册会话:向SessionTracker注册会话。SessionTracker中维护了两个比较重要的数据结构,分别是sessionsWithTimeout和sessionsById。前者根据sessionID保存了所有会话的超时时间,而后者根据sessionID保存了所有会话实体。

10.激活会话:为会话安排一个区别,以便会话清理程序能够高效地进行会话清理。

11.生成会话密码:服务端在创建一个客户端会话的时候,会同时为客户端生成一个会话密码,连同sessionID一起发送给客户端,作为会话在集群中不同机器间转移的凭证。

预处理

12.将请求交给ZooKeeper的PrepRequestProcessor处理器进行处理:在提交该请求处理器之前,需要确保当前会话处于激活状态。

13.创建请求事务头:对于请求事务,ZooKeeper首先会为其创建请求事务头,包括sessionID、ZXID、CXID和请求类型等。

14.创建请求事务体:对于事务请求,ZooKeeper还会为其创建请求事务体。

15.注册与激活会话:此处会话注册与激活的目的是处理非Leader服务器转发过来的会话创建请求。

事务处理

16.将请求交给ProposalRequestProcessor处理器:该处理器涉及事务请求的投票流程,流程分别为Sync流程(使用SyncRequestProcessor处理器记录事务日志的过程)、Proposal流程(投票过程)和Commit流程(CommitProcessor处理器将请求放入queuedRequests队列,需要等待其它事务请求的投票过程结束再作提交处理)。

事务应用

17.交付给FinalRequestProcessor处理器:FinalRequestProcessor处理器首先检查outstandingChanges队列中请求的有效性,如果发现这些请求已经落后于当前正在处理的请求,那么直接从outstandingChanges队列中移除。

18.事务应用:需要将事务变更应用到内存数据库中。如果是会话创建则无需对内存数据库做任何处理。

19.将事务请求放入队列:一旦完成事务请求的内存数据库应用,就可以将请求放入commitProposal队列中。该队列用来保存最近被提交的事务请求,以便集群间机器进行数据的快速同步。

会话响应

20.统计处理:统计客户端连接的基本信息。

21.创建响应ConnectResponse:ConnectResponse是一个会话创建成功后的响应,包含了当前客户端与服务端之间的通信协议版本号、会话超时时间、sessionID和会话密码。

22.序列化ConnectResponse。

23.I/O层发送给客户端

猜你喜欢

转载自blog.csdn.net/carson0408/article/details/84193056