Zookeeper学习笔记——Zookeeper会话

会话是Zookeeper中的重要概念之一,客户端与服务端之间的任何交互操作都与会话相关,比如:临时节点的生命周期、客户请求的顺序执行、Watcher通知机制等。
1、会话状态
Zookeeper的会话状态可分为CONNECTING、CONNECTED、RECONNECTING、RECONNECTED和CLOSE等。
开始创建Zookeeper句柄时,会话的状态为CONNECTING,同时,客户端会在服务器地址列表中逐一选取IP地址来尝试连接,直到成功连接上为止,此时会话状态为CONNECTED。
如果因为网络或其他原因,客户端与服务端之间连接断开,则Zookeeper客户端会自动进行重连,同时会话状态变成CONNECTING,直到重新连接上Zookeeper之后,会话状态才会变成CONNECTED。一般情况下,会话状态处于CONNECTING和CONNECTED之间。
如果出现会话超时、权限检查失败或客户端主动退出等情况,那么会话状态会直接变成CLOSE。
Zookeeper客户端会话状态状态机如图1所示。
Zookeeper学习笔记——Zookeeper会话_第1张图片
图1 Zookeeper客户端会话状态机
2、会话创建
Session是Zookeeper的会话实体,代表客户端会话,具有以下四个属性:
sessionID:会话ID,唯一标识一个会话,每次会话创建时,Zookeeper都会为其分配一个全局唯一的sessionID;
TimeOut:会话超时事件;
TickTime:下次会话超时时间点,它是一个13位的long型数据,其值接近与当前时间加上TimeOut,但不完全相等;
isClosing:标记会话是否已经被关闭,当服务端检测到会话超时失效时,会将会话标记该属性,确保后续不再处理该会话的请求;
(1)sessionID
sessionID为64为的长整型数据,其的生成算法:高8位为机器标识(SID,即配置文件myid中的值),低56位为会话生成的时间点的毫秒表示。
3、会话管理
(1)分桶策略
SessionTracker负责Zookeeper的会话管理,其采用了分桶策略,即:将类似的会话放在同一区块中进行管理,以便Zookeeper对会话进行不同区块的隔离处理以及同一区块的统一处理,如图2所示。
Zookeeper学习笔记——Zookeeper会话_第2张图片
图2 Session的分桶管理策略
如图所示,Zookeeper将所有会话分在不同的区块中,分配的原则是会话的下次超时时间点(Expiration Time)。Expiration Time是指会话最近一次可能超时的时间点,一个新建会话的Expiration Time的计算方式如下:
Expiration Time = Current Time + Session TimeOut (单位:毫秒)
Zookeeper的Leader服务器在运行过程中会定时检查会话是否超时,时间间隔是Expiration Interval(单位:毫秒),默认为tickTime的值,Expiration Time的计算方法如下:
ExpirationTime = ((Current Time + Session TimeOut) / Expiration Interval + 1) * Expiration Interval
因此,图2中的横坐标Expiration Time值总是Expiration Interval的整数倍。
(2)会话激活
为了保持会话的有效性,客户端会在会话超时时间到期之前向服务端发送PING请求来保持会话的有效性(俗称:“心跳检测”)。同时,服务端需要不断接受客户端的心跳检测,并重新激活会话(此过程称为Touch Session),会话激活既能使服务端检测到客户端的存活性,也能让客户端保持连接状态。其主要流程如图3所示。
Zookeeper学习笔记——Zookeeper会话_第3张图片
图3 会话激活流程
如图3所示,会话激活流程分为四步:
1.检查会话是否已经关闭,若已关闭,则不再激活会话;
2.计算会话新的超时时间ExpirationTime_New;
3.定位会话的当前区块:获取会话上次超时时间ExpirationTime_Old;
4.迁移会话:将会话从老的区块中取出放入到ExpirationTime_New对应的区块中。
Zookeeper学习笔记——Zookeeper会话_第4张图片
图4 会话迁移
在Zookeeper中,只要客户端发送请求到服务端就会触发一次会话激活,一下两种情况都会触发会话激活:
1.客户端向服务端发送请求,包括读写请求;
2.如果xia客户端发现在sessionTimeout/3时间内尚未和服务端进行任何通讯,则会主动发送PING请求,服务端收到PING请求后,会触发会话激活。
(3)会话超时检查
在Zookeeper中,SessionTracker有个单独的线程(“超时检查线程”)负责会话超时检查,工作机制为:逐一堆会话桶中剩余的会话进行清理。
如果一个会话呗激活,则Zookeeper会将其从一个会话桶中迁移到下一个会话桶中,此时,老的会话桶中的会话都是尚未被激活的,超时线程就是定时检查这个会话桶中所有剩下的未被迁移的会话。
由于Zookeeper是以Expiration Interval的整数倍作为时间轴的,所以,超时检查线程只需要在指定事件点(比如:Expiration Time1、Expiration Time2 …)上进行检查即可。
4、会话清理
会话超时线程检查出已经过期的会话后,SessionTracker就开始进行会话清理工作,大体分为以下七步:

1.标记会话状态为“已关闭”:在会话清理期间不再处理该会话的请求;
2.发起“会话关闭”请求:Zookeeper使用提交会话关闭请求的方式使得对该会话的关闭操作在整改集群都生效;
3.收集需要清理的临时节点; Zookeeper的内存数据库为每个会话单独保存了临时节点列表。但是,在处理会话关闭请求之前,若正好有以下两个请求到达服务端并正在处理中:
① 节点删除请求:删除的目标节点是临时节点列表中的一个;
② 临时节点创建请求:创建的目标是临时节点列表中的一个;
对于第一个请求,需要将所有请求对应的节点路径从临时节点列表中移除,避免重复删除;对于第二个请求,需要将所有这些请求对应的节点路径添加到临时节点列表中,以删除这些即将被创建但是尚未保存到内存数据库中的临时节点。
4.添加“节点删除”事务变更:逐个为要清理的临时节点构建“节点删除”请求; 5.删除临时节点;
6.移除会话:将会话从SessionTracker中移除;
7.关闭NIOServerCnxn。

5、重连
当客户端与服务端之间的连接断开时,客户端会自动尝试重连,知道最终成功连接上。在此情况下,再次连接上服务器的客户端可能处于以下两种状态之一:
1.CONNECTED:会话超时时间内重新连接上集群中的服务器;
2.EXPIRED:会话超时时间之外重新连接上集群中的服务器,服务端已经将该会话清理,此时会话被视为非法会话。
正常情况下,客户端会话是一直有效的,但是,当客户端与服务端之间的连接断开后,客户端会看到以下两种异常:CONNECTION_LOSS(连接断开)和SESSION_EXPIRED(会话过期)。
(1)CONNECTION_LOSS(连接断开)
网络闪断或与客服端连接的服务器出现异常导致的连接断开,统称为“客户端与服务器俩解决断开”现象,即:CONNECTION_LOSS。
在此情况下,客户端会自动从服务器地址列表中重新逐个选取新的地址,并尝试重新连接,知道最终成功连接上服务器。
客户端收到CONNECTION_LOSS事件候,需要等待客户端自动完成重连,然后检测上次操作的执行情况,比如:检查znode是否存在以判断是否创建成功;检查znode数据已判断是否更新成功。
(2)SESSION_EXPIRED(会话过期)
客户端与服务端断开连接后,如果重连时间超过了会话超时时间,则服务器会进行会话清理。此时,客户端不知道会话已经失效,状态还是DISCONNECTED,如果客户端重新连上了服务器,状态为SESSION_EXPIRED,则客户端需要重新实例化Zookeeper对象,并且重新恢复临时数据。
(3)SESSION_MOVED
客户端会话从一台服务器转移到另一台服务器,即:客户端与服务端S1断开连接后,重连上了服务端S2,此时会话就从S1转移到了S2。当多个客户端使用相同的sessionId/sessionPasswd创建会话时,会收到SessionMovedException异常。因为一旦有第二个客户端连接上了服务端,就被认为是会话转移了。

你可能感兴趣的:(Zookeeper)