zookeeper原理篇-Zookeeper会话机制

前言

上篇文章我们学习了Zookeeper的选举流程和FastLeaderElection选举算法的实现过程,了解了Zookeeper从初始化开始到选举的过程,本篇文章我们开始研究Zookeeper中的会话机制体系

会话

在Zookeeper中,会话是个很重要的概念之一,客户端与服务端之间的任何交互操作都和会话息息相关,其中包含zookeeper的临时节点的生命周期、客户端请求执行以及Watcher通知机制等。接下来,我们从全局的会话状态变化创建会话再到会话管理三个方面来看看Zookeeper是如何处理会话相关的操作

会话状态

客户端需要与服务端创建一个会话,这个时候客户端需要提供一个服务端地址列表,“ host1 : port,host2: port ,host3:port ” ,根据地址开始创建zookeeper对象,这个时候客户端的状态则变更为CONNECTION,同时客户端会根据上述的地址列表,按照顺序的方式获取IP来尝试建立网络连接,直到成功连接上服务器,这个时候客户端的状态就可以变更为CONNECTED。在zookeeper服务端提供服务的过程中,有可能遇到网络波动等原因,导致客户端与服务端断开了连接,这个时候客户端会进行重新连接操作,这个时候的状态为CONNECTION,当连接再次建立后,客户端的状态会再次更改为CONNECTED,也就是说只要在zookeeper运行期间,客户端的状态总是能保持在CONNECTION或者是CONNECTED。当然在建立连接的过程中,如果出现了连接超时、权限检查失败或者是在建立连接的过程中,我们主动退出连接操作,这个时候客户端的状态都会变成CLOSE状态。

会话创建
Session

Session是Zookeeper中会话的实例载体,一个Session则是指代一个客户端会话。一个会话必须包含以下几个基本的属性:

  • SessionID : 会话的ID,用来唯一标识一个会话,每一次客户端建立连接的时候,Zookeeper服务端都会给其分配一个全局唯一的sessionID

  • TimeOut:一次会话的超时时间,客户端在构造Zookeeper实例的时候,会配置一个sessionTimeOut参数用于指定会话的超时的时间。Zookeeper服务端会按照连接的客户端发来的TimeOut参数来计算并确定超时的时间

  • TickTime:下一次会话超时的时间点,为了方便Zookeeper对会话进行所谓的分桶策略进行管理,同时也可以实现高效的对会话的一个检查和清理。TickTime是一个13位的Long类型的数值,一般情况下这个值接近TimeOut,但是并不完全相等

  • isCloseing:用来标记当前会话是否已经处于被关闭的状态。如果服务端检测到当前会话的超时时间已经到了,就会将isCloseing属性标记为已经关闭,这样以后即使再有这个会话的请求访问也不会被处理

SessionID

SessionID作为一个全局唯一的标识,我们可以来探究下Zookeeper是如何保证Session会话在集群环境下依然能保证全局唯一性的:

sessionTracker初始化的时候,会调用initializeNextSession来生成session,算法大概如下:

  1. public s ta tic long initializeNextSession(long id) {

  2. long nextSid = 0;

  3. nextSid = (System.currentTim eM illis() « 24) » 8;

  4. nextSid = nextSid | (id « 56);

  5. return nextSid;

  6. } }

从这段代码,我们可以看到session的创建大概分为以下几个步骤:

1.获取当前时间的毫秒表示

我们假设当前System.currentTimeMills()获取的值是1380895182327,其64位二进制表示为:

00000000 00000000 00000001 01000001 10000011 11000100 01001101 11110111

2.接下来左移24位,我们可以得到结果:

01000001 100000011 11000100 01001101 11110111 00000000 00000000 00000000,可以看到低位已经把高位补齐,剩下的低位都使用了0补齐

3.右移8位,结果变成了:

00000000 01000001 100000011 11000100 01001101 11110111 00000000 00000000

4.计算机器码标识ID

在initializeNextSession方法中,出现了一个id变量,这个变量就是生成的SID的值,而SID在部署的时候就是我们在myid中配置的值,一般是一个整数,假设此时的值为2,转为64位二进制表示:

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000010

此时发现高位几乎都是0,进行左移56位以后,得到值如下:

00000010 00000000 00000000 00000000 00000000 00000000 00000000 00000000

5.将前面第三步和第四步得到的结果进行 | 操作:

可以得到结果为:

00000010 01000001 10000011 11000100 01001101 11110111 00000000 00000000

这个时候我们可以得到一个单机中唯一的序列号ID,整个算法大概可以理解为,先通过高8位确定机器以后,后面的56位按照毫秒进行随机,可以看出来当前的算法!还是蛮严谨的,基本上看不出来什么明显的问题,但是其实也有问题的,其中我们可以看到,zk选择了当前机器时间内的毫秒作为基数,但是如果时间到了2022年4月8号以后, System . currentTimeMillis ()的值会是多少呢?

  1. Date d = newDate(2022-1900 f 3,8);

  2. System. out. p rin tln ( Long. toBinaryString(d .getTime()));

打印出来的结果为:

  1. 0000000000000000000000011000000000000100110000010000010000000000

接着我们左移24位以后会发现,这个时候的值依然是个负数,所以我们为了保证不会出现负数的情况,解决方案如下:

  1. publicstaticlong initializeNextSession(long id { ) {

  2. long nextSid = 0;

  3. nextSid = (System.currentTim eM illis() « 24) > » 8;

  4. nextSid = nextSid | (id « 56);

  5. return nextSid;

  6. } }

这样就可以避免生成的时候出现负数了

SessionTracker

SessionTracker是Zookeeper中的会话管理器,负责整个zk生命周期中会话的创建管理清理操作,而每一个会话在Sessiontracker内部都保留了三份,大体如下:

1.sessionsWithTimeout这是一个ConcurrentHashMap<long,integer style=“margin: 0px; padding: 0px; box-sizing: border-box;”>类型的数据结构,用来管理会话的超时时间,这个参数会被持久化到快照文件中去</long,integer>

2.sessionsById是一个HashMap<long,integer style=“margin: 0px; padding: 0px; box-sizing: border-box;”>类型的数据结构,用于根据sessionId来管理session实体</long,integer>

3.sessionsSets同样也是一个HashMap<long,integer style=“margin: 0px; padding: 0px; box-sizing: border-box;”>类型的数据结构,用来会话超时的时候进行归档,便于进行会话恢复和管理</long,integer>

会话创建

创建会话的过程,大体可以分为几个步骤,分别是处理ConnectRequest请求、创建会话、处理器链路处理和响应,在zk服务端中,首先是NIOServerCnxn来负责接受来自客户端的会话创建请求,并且进行反序列化工作,然后开始分配超时时间。分配完毕后,会开始创建sessionId,并且将其注册到SessionsById和sessionsWithTimeOut,进行激活,这个时候就可以考虑处理流转。

会话管理

Zookeeper中的会话管理主要是SesssionTracker负责的,内部使用了一个特殊的机制,称之为分桶策略,所谓分桶策略,其实是将类似的会话放在一个区块中进行管理,以便于zookeeper对会话进行不同区块的隔离以及同一区块的统一处理

从图中我们可以看到,所有的会话都分配在了不同的区块中,分配原则是每个会话的下个超时的时间点,ExpiractionTime是指最近一次可能过期的时间点,每一个会话的ExpiractionTime的计算方式如下:

ExpiractionTime = CurrentTime + SessionTimeout
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img
线程、数据库、算法、JVM、分布式、微服务、框架、Spring相关知识

一线互联网P7面试集锦+各种大厂面试集锦

学习笔记以及面试真题解析

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
面试真题解析

[外链图片转存中…(img-qktMZs9W-1713439782200)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值