ZooKeeper系统模型之会话管理。

分桶策略

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

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

        其中CurrentTime指当前时间,单位是毫秒;SessionTimeout指该会话设置的超时时间,单位也是毫秒。那么,上图中横坐标所标识的时间,是否就是通过上述公式计算出来的呢?答案是否定的,在ZooKeeper的实际实现中,还做了一个处理。ZooKeeper的Leader服务器在运行期间会定时的进行会话超时检查,其时间间隔是ExpirationInterval,单位是毫秒,默认值是tickTime的值,即默认情况下,每隔2000毫秒进行一次会话超时检查。为了方便对多个会话同时进行超时检查,完整的ExpirationTime的计算方式如下:

        也就是说,上图中横坐标的ExpirationTime值总是ExpirationInterval的整数倍数。举个实际例子,假设当前时间的毫秒表示是1370907000000,客户端会话设置的超时时间是15000毫秒,ZooKeeper服务器设置的tickTime为2000毫秒,那么ExpirationInterval的值同样为2000毫秒,于是我们可以计算该会话的ExpirationTime值为1370907016000,计算过程如下:

会话激活

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

  • 检验该会话是否已经被关闭。

Leader会检查该会话是否已经被关闭,如果该会话已经被关闭,那么不再继续激活该会话。

  • 计算该会话新的超时时间ExpirationTime_New。

如果该会话尚未关闭,那么就开始激活会话。首先需要计算出该会话下一次超时时间点,使用的就是上面提到的计算公式。

  • 定位该会话当前的区块。

获取该会话老的超时时间ExpirationTime_Old,并根据该超时时间来定位到其所在的区块。

  • 迁移会话。

将该会话从老的区块中取出,放入ExpirationTime_New对应的新区块中,如下图所示。

        通过以上4步,就基本完成会话激活的过程。在上面的会话激活过程中,我们可以看到,只要客户端发来心跳检测,那么服务端就会进行依次会话激活。心跳检测由客户端主动发起,以PING请求的形式向服务端发送。但实际上,在ZooKeeper服务端的设计中,只要客户端有请求发送到服务端,那么就会触发一次会话激活。因此,总的来讲,大体会出现以下两种情况下的会话激活。

  • 只要客户端向服务端发送请求,包括读或写请求,那么就会触发一次会话激活。
  • 如果客户端发现在sessionTimeout/3时间内尚未和服务器进行过任何通信,即没有向服务端发送任何请求,那么就会主动发起一个PING请求,服务端收到该请求后,就会触发上述第一种情况下的会话激活。

会话超时检查

        上面我们分别介绍了ZooKeeper会话的分桶管理策略和会话激活的过程,现在我们再来看看ZooKeeper是如何进行会话超时检查的。

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

        在第一个图中,我们可以看到,如果一个会话被激活,那么ZooKeeper会将其从上一个会话桶迁移到下一个会话桶中,例如图中的session.n这个会话,由于触发了会话激活,因此ZooKeeper会将其从expirationTime 1 桶迁移到 expirationTime n 桶中去。于是,expirationTime 1 中留下的所有会话都是尚未被激活的。因此,超时检查线程的任务就是定时检查出这个会话桶中所有剩下的未被迁移的会话。

        那么超时检查线程是如何做到定时检查的呢?这里就和ZooKeeper会话的分桶策略紧密联系起来了。在会话分桶策略中,我们将ExpirationInterval的倍数作为时间点来分布会话,因此,超时检查线程只要在这些指定的时间点上进行检查即可,这样即提高了会话检查的效率,而且由于是批量处理,因此性能非常好——这也是为什么ZooKeeper要通过分桶策略来管理客户端会话的最主要的原因。因为在实际生产环境中,一个ZooKeeper集群的客户端会话数可能会非常多,逐个依次检查会话的方式会非常耗费时间。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值