zookeeper会话

会话(Session)是ZooKeeper中最重要的概念之一,客户端和服务端之间的任何交互操作都与会话息息相关,这其中就包括临时节点的生命周期、客户端请求的顺序执行以及Watcher通知机制等。

1. 会话状态

在ZooKeeper客户端和服务端成功完成连接创建后,就建立了一个会话。ZooKeeper会话在整个运行期间的声明周期中,会在不同的会话状态之间进行切换,这些状态一般可以分为CONNECTING、CONNECTED、RECONNECTING、RECONNECTED和CLOSE等。

如果客户端需要与服务端创建一个会话,那么客户端必须提供一个使用字符串表示的服务器地址列表:“host1:port,host2:port,host3:port”。一旦客户端开始创建ZooKeeper对象,那么客户端状态就会变成CONNECTING,同时客户端开始从上述服务器地址列表中逐个选取IP地址来尝试进行网络连接,直到成功连接上服务器,然后将客户端状态变更为CONNECTED。

通常,伴随着网络闪断或是其他原因,客户端和服务器之间的连接会出现断开情况。一旦碰到这种情况,ZooKeeper客户端会自动进行重连操作,同时客户端的状态再次变为CONNECTING,直到重新连接上ZooKeeper服务器后,客户端状态又会再次转变成CONNECTED。因此,在通常情况下,在ZooKeeper运行期间,客户端的状态总是介于CONNECTING和CONNECTED两者之一。

另外,如果出现诸如会话超时、权限检查失败或是客户端主动退出程序等情况,那么客户端的状态就会直接变为CLOSE。

2. 会话创建

Session

Session是ZooKeeper中的会话实体,代表了一个客户端会话。其包含以下4个基础属性、

  • sessionId:会话id,用来唯一标识一个会话,每次客户端创建新会话的时候,ZooKeeper都会为其分配一个全局唯一的sessionId。
  • TimeOut:会话超时时间。客户端在构造ZooKeeper实例的时候,会配置一个sessionTimeout参数用于指定会话的超时时间。ZooKeeper客户端向服务器发送这个超时时间后,服务器会根据自己的超时时间限制最终确定会话的超时时间。
  • TickTime:下次会话超时时间点。
  • isClosing:该属性用于标记一个会话是否已经被关闭。

sessionID

在SeesionTracker初始化的时候,会调用initializeNextSession方法来生成一个初始化的sessionID,之后在ZooKeeper的正常运行过程中,会在该sessionID的基础上为每个会话进行分配,其初始化算法如下:

public static long initializeNextSeesion(long id) {
    long nextSid = 0;
    nextSid = (System.currentTimeMillis() << 24) >> 8;
    nextSid = nextSid | (id << 56);
    return nextSid;
}

上面这个方法就是ZooKeeper初始化sessionID的算法,我们一起深入的探究下。从上面的代码片段中,可以看出sessionID的生成大体可以分为以下5个步骤。

  1. 获取当前的毫秒表示。
  2. 左移24位。
  3. 右移8位。
  4. 添加机器标识:SID。
  5. 将步骤3和步骤4得到的两个64位表示的数值进行“|”操作。

简单地讲,可以将上述算法概括为:高8位确定了所在机器,后56位使用当前时间的毫秒进行随机。

SessionTracker

SessionTracker是ZooKeeper服务端的会话管理器,负责会话的创建、管理和清理等工作。可以说,整个会话的生命周期都离不开SessionTracker的管理。每一个会话在SessionTracker内部都保留了三份,具体如下。

  • sessionsById:这是一个HashMap<Long, SeesionImpl>类型的数据结构,用于根据sessionID来管理Session实体。
  • sessionsWithTimeout:这是一个ConcurrentHashMap<Long, Integer>类型的数据结构,用于根据sessionID来管理会话的超时时间。该数据结构和ZooKeeper内存数据库相连通,会被定期持久化到快照文件中去。
  • sessionSets:这是一个HashMap<Long, SessionSet>类型的数据结构,用于根据下次会话超时时间来归档会话,便于进行会话管理和超时检查。

创建连接

服务端对于客户端的“会话创建”请求的处理,大体可以分为四大步骤,分别是ConnectRequest请求、会话创建、处理器链路处理和会话响应。

3. 会话管理

分桶策略

ZooKeeper的会话管理主要是由SessionTracker负责的,其采用了一种特殊的会化管理方式,我们称之为“分桶策略”。所谓分桶策略,是指将类似的会话放在同一区块中进行管理,以便于ZooKeeper对会话进行不同区块的格里处理以及同一区块的统一处理。

ZooKeeper将所有的会话都分配在了不同的区块之中,分配的原则是每个会话的“下次超时时间点”(ExpirationTime)。ExpirationTime是指该会话最近一次可能超时的时间点,对于一个新创建的会话而言,其会话创建完毕后,ZooKeeper就会为其计算ExpirationTime,计算方式如下:

ExpirationTime = CurrentTime + SessionTimeout

在ZooKeeper的实际实现中,Zookeeper的Leader服务器在运行期间会定时的进行会话超时检查,其时间间隔是ExpirationInterval,单位是毫秒,默认值是tickTime的值,即默认情况下,每隔2000毫秒进行一次会话超时检查。为了方便对多个会话同时进行超时检查,完整的ExpirationTime的计算方式如下:

ExpirationTime_ = CurrentTime + SessionTimeout
ExpirationTime = (ExpirationTime_/ExpirationInterval + 1) * ExpirationInterval

会话激活

为了保持客户端会话的有效性,在ZooKeeper的运行过程中,客户端会在会话超时时间国企范围内向服务端发送PING请求来保持会话的有效性,我们俗称“心跳检测”。同时,服务端需要不断地接收来自客户端的这个心跳检测,并且需要重新激活对应的客户端会话,我们将这个重新激活的过程称为TouchSession。会话激活的过程,不仅能够使服务端检测到对应客户端的存活性,也能让客户端自己保持连接状态。

会话超时检查

在ZooKeeper中,会话超时检查同样是由SessionTracker负责的。SessionTracker中有一个单独的线程专门进行会话超时检查,这里我们称其为“超时检查线程”,其工作机制的核心思路非常简单:逐个依次对会话桶中剩下的会话进行清理。

4. 会话清理

当SessionTracker的会话超时检查线程整理出一些已经过期的会话后,那么就要开始进行会话清理了。会话清理的步骤大致可以分为以下七步。

4.1 标记会话状态为“已关闭”

为了保证在清理期间不再处理来自该客户端的新请求,SessionTracker会首先将该会话的isClosing属性标记为true。

 4.2 发起“会话关闭”请求

为了使该会话的关闭操作在整个服务端集群中都生效,ZooKeeper使用了提交“会话关闭”请求的方式,并立即交付给PrepRequestProcessor处理器进行处理。

4.3 收集需要清理的临时节点

在ZooKeeper的内存数据库中,为每个会话都单独保存了一份由该会话维护的所有临时节点集合,因此在会话清理阶段,只需要根据当前即将关闭的会话的sessionID从内存数据库中获取到这份临时节点列表即可。

实际上,有如下细节需要处理:在ZooKeeper处理会话关闭请求之前,正好有以下请求到达了服务端并正在处理中:

  • 节点删除请求,删除的目标节点正好是上述临时节点中的一个。
  • 临时节点创建请求,创建的目标节点正好是上述临时节点中的一个。

假定我们当前获取的临时节点列表是ephemerals,那么针对第一类请求,我们需要将所有这些请求对应的数据节点路径从ephemerals中移除,以避免重复删除。针对第二类,我们需要将所有这些请求对应的数据节点路径添加到ephemerals中去,以删除这些即将会被创建但是尚未保存到内存数据库中去的临时节点。

4.4 添加“节点删除”事务变更

完成该会话相关的临时节点收集后,ZooKeeper会逐个将这些临时节点转换成“节点删除”请求,并放入事务变更队列outstandingChanges中去。

4.5 删除临时节点

FinalRequestProcessor处理器会触发内存数据库,删除该会话对应的所有临时节点。

4.6 移除会话

完成节点删除后,需要将会话从SessionTracker中移除。主要就是从上面提到的三个数据结构(sessionById、sessionsWithTimeout和sessionSets)中将该会话移除掉。

4.7 关闭NIOServerCnxn

最后,从NIOServerCnxnFactory找到该会话对应的NIOServerCnxn,将其关闭。

5. 重连

当客户端和服务端之间的网络连接断开时,ZooKeeper客户端会自动进行反复的重连,知道最终成功连接上ZooKeeper集群中的一台机器。在这种情况下,再次连接上服务端的客户端有可能会处于以下两种状态之一。

  • CONNECTED:重连成功
  • EXPIRED:如果是在会话超时时间以外重新连接上,那么服务端其实已经对该会话进行了会话清理操作,因此再次连接上的会话将被视为非法会话。

当客户端和服务端之间的连接断开后,用户在客户端可能会看到两类异常:CONNECTION_LOSS(连接断开)和SESSION_EXPIRED(会话过期)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值