zk维护的数据主要有:客户端的会话(session)状态及数据节点(dataNode)信息。zk在内存中构造了个DataTree的数据结构,维护着path到dataNode的映射以及dataNode间的树状层级关系。为了提高读取性能,集群中每个服务节点都是将数据全量存储在内存中。可见,zk最适于读多写少且轻量级数据(默认设置下单个dataNode限制为1MB大小)的应用场景。数据仅存储在内存是很不安全的,zk采用事务日志文件及快照文件的方案来落盘数据,保障数据在不丢失的情况下能快速恢复。上篇文章学习了节点相关的内容,这篇看一下session相关的内容:

指zk客户端与zk服务器之间的会话,在zk中,会话是通过客户端和服务器之间的一个TCP长连接来实现的。通过这个长连接,客户端能够使用心跳检测与服务器保持有效的会话,也能向服务器发送请求并接收响应,还可接收服务器的Watcher事件通知。Session的sessionTimeout,是会话超时时间,如果这段时间内,客户端未与服务器发生任何沟通(心跳或请求),服务器端会清除该session数据,客户端的TCP长连接将不可用,这种情况下,客户端需要重新实例化一个Zookeeper对象。在ZooKeeper客户端与服务端成功完成建立连接后,就建立了一个会话。ZooKeeper会话在整个运行期间的生命周期中,会在不同的会话状态之间进行切换,这些状态一般可以分为CONNECTING、CONNECTED、RECONNECTING、RECONNECTED和CLOSE等。Session 是ZooKeeper中最重要的概念之一。它包括4个基本属性:

  • sessionID:会话ID,唯一标识一个会话,每次客户端创建新会话的时候,ZooKeeper都会为其分配一个全局唯一的sessionID。
  • TimeOut:会话超时时间。客户端在构造ZooKeeper实例的时候,会配置一个sessionTimeOut参数用于指定会话超时时间。ZooKeeper客户端向服务器发送这个超时时间后,服务器会根据自己的超时时间限制最终确定会话的超时时间。
  • TickTime:下次会话超时时间点。为了便于ZooKeeper对会话实行“分桶策略”管理,同时也是为了高效低耗地实现的超时检测与清理,ZooKeeper会为每个会话标识一个下次会话超时时间。
  • isClosing:该属性用于标记一个会话是否被关闭。通常当服务端检测到一个会话已经超时失效的时候,会将该会话的isClosing属性标记为“已关闭”,这样就能确保不再处理来自该会话的新请求了。

Zk客户端通过使用语言绑定(language binding)创建一个service的handle,来和zk service建立session。一旦创建,此handle初始为CONNECTING状态,然后client将会尝试与zk service中的一台server建立链接,链接成功后,状态将会被转换为CONNECTED。在一般情况下,session会是这两个状态中的一种。不过,当发生不可恢复时,例如session过期或者验证失败,或者应用明确的关闭了handle,那么此session的handle将会被变更为CLOSED状态。下图为session状态转换(来自apache zookeeper官网)

当client从zk service中获取一个handle(句柄)之后,zk将会为client创建一个session,sessionID为一个64位的数字。如果client链接到了其他的server上,它(client)将会把session id作为“握手”链接的一部分发送给server。因为安全的因素,server还为session id创建了一个password,以便任何ZK server都能够验证。当session创建成功后,session id和password都将会发送给client。无论client和哪个server建立链接,它都必须将session id和password一同发送给需要建立链接的server。当client连接失效后,它将会检索指定的server列表,并与其中一个server重新建立链接,session的状态被再次转换为CONNECTED(在session timeout有效期内),或者将会被转换成“EXPIRED”状态(session timeout之后,建立了链接)。不建议在链接失效后,创建新的session(Zookeeper实例),ZK client将会为你处理重链接。此外,ZK内置的一些机制来处理类似“羊群效应”等等。当client被通知session过期,只需要创建一个新的session即可。

Client与Server持续通讯时,也意味着Session是"活跃"的(sessionId将会伴随每次请求交付给server),如果session空闲一段时间,这将会导致过期,所以client会发送一种PING类型的请求来保持session的alive,PING请求不仅可以让server知道client仍然存活,而且它也能够验证当前zk server是否alive

会话创建

这里就讲最底层的会话创建以及会话的数据结构,参照 SessionTrackerImpl.SessionImpl数据结构

    public static class SessionImpl implements Session {SessionImpl(long sessionId, int timeout, long expireTime) {this.sessionId = sessionId;this.timeout = timeout;this.tickTime = expireTime;isClosing = false;}final long sessionId;//会话id,全局唯一final int timeout;//会话超时时间long tickTime;//下次会话的超时时间点,会不断刷新boolean isClosing;//是否被关闭,如果关闭则不再处理该会话的新请求Object owner;public long getSessionId() { return sessionId; }public int getTimeout() { return timeout; }public boolean isClosing() { return isClosing; }}

sessionId唯一性的保证

会话id要保证全局唯一,算法如下

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

id表示配置在myid文件中的值,通常是一个整数,如1、2、3。该算法的高8位确定了所在机器,后56位使用当前时间的毫秒表示进行随机。

会话管理

主要分为,分桶策略,会话激活,超时检测,会话清理

分桶策略

Zookeeper的会话管理主要是通过SessionTracker来负责,其采用了分桶策略(将类似的会话放在同一区块中进行管理)进行管理,以便Zookeeper对会话进行不同区块的隔离处理以及同一区块的统一处理。

Zookeeper将所有的会话都分配在不同的区块中,分配的原则是每个会话的下次超时时间点(ExpirationTime)。ExpirationTime指该会话最近一次可能超时的时间点。同时,Zookeeper Leader服务器在运行过程中会定时地进行会话超时检查,时间间隔是ExpirationInterval,默认为tickTime的值,ExpirationTime的计算时间如下:

  ExpirationTime = ((CurrentTime + SessionTimeOut) / ExpirationInterval + 1) * ExpirationInterval

会话激活

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

如上图所示,整个流程分为四步:

  1. 检查该会话是否已经被关闭。若已经被关闭,则直接返回即可。
  2. 计算该会话新的超时时间ExpirationTime_New。使用上面提到的公式计算下一次超时时间点。
  3. 获取该会话上次超时时间ExpirationTime_Old。计算该值是为了定位其所在的区块。
  4. 迁移会话。将该会话从老的区块中取出,放入ExpirationTime_New对应的新区块中。

在上面会话激活过程中,只要客户端发送心跳检测,服务端就会进行一次会话激活,心跳检测由客户端主动发起,以PING请求形式向服务端发送,在Zookeeper的实际设计中,只要客户端有请求发送到服务端,那么就会触发一次会话激活,以下两种情况都会触发会话激活。

  1. 客户端向服务端发送请求,包括读写请求,就会触发会话激活。
  2. 客户端发现在sessionTimeout/3时间内尚未和服务端进行任何通信,那么就会主动发起PING请求,服务端收到该请求后,就会触发会话激活。

超时检测

对于会话的超时检查而言,Zookeeper使用SessionTracker来负责,SessionTracker使用单独的线程(超时检查线程)专门进行会话超时检查,即逐个一次地对会话桶中剩下的会话进行清理。如果一个会话被激活,那么Zookeeper就会将其从上一个会话桶迁移到下一个会话桶中,如ExpirationTime 1 的session n 迁移到ExpirationTime n 中,此时ExpirationTime 1中留下的所有会话都是尚未被激活的,超时检查线程就定时检查这个会话桶中所有剩下的未被迁移的会话,超时检查线程只需要在这些指定时间点(ExpirationTime 1、ExpirationTime 2…)上进行检查即可,这样提高了检查的效率,性能也非常好。

会话清理

当SessionTracker的会话超时线程检查出已经过期的会话后,就开始进行会话清理工作,大致可以分为如下七步。
  1. 标记会话状态为已关闭。由于会话清理过程需要一段时间,为了保证在此期间不再处理来自该客户端的请求,SessionTracker会首先将该会话的isClosing标记为true,这样在会话清理期间接收到该客户端的心情求也无法继续处理了。
  2. 发起会话关闭请求。为了使对该会话的关闭操作在整个服务端集群都生效,Zookeeper使用了提交会话关闭请求的方式,并立即交付给PreRequestProcessor进行处理。
  3. 收集需要清理的临时节点。一旦某个会话失效后,那么和该会话相关的临时节点都需要被清理,因此,在清理之前,首先需要将服务器上所有和该会话相关的临时节点都整理出来。Zookeeper在内存数据库中会为每个会话都单独保存了一份由该会话维护的所有临时节点集合,在Zookeeper处理会话关闭请求之前,若正好有以下两类请求到达了服务端并正在处理中。

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

对于第一类请求,需要将所有请求对应的数据节点路径从当前临时节点列表中移出,以避免重复删除,对于第二类请求,需要将所有这些请求对应的数据节点路径添加到当前临时节点列表中,以删除这些即将被创建但是尚未保存到内存数据库中的临时节点。
  4. 添加节点删除事务变更。完成该会话相关的临时节点收集后,Zookeeper会逐个将这些临时节点转换成"节点删除"请求,并放入事务变更队列outstandingChanges中。
  5. 删除临时节点。FinalRequestProcessor会触发内存数据库,删除该会话对应的所有临时节点。
  6. 移除会话。完成节点删除后,需要将会话从SessionTracker中删除。
  7. 关闭NIOServerCnxn。最后,从NIOServerCnxnFactory找到该会话对应的NIOServerCnxn,将其关闭。

参考地址:

https://www.jianshu.com/p/3b7f9a032ded

https://juejin.im/post/5d2d33b5e51d4510803ce461

https://www.jianshu.com/p/594129a44814

https://www.cnblogs.com/aoshicangqiong/p/8024333.html

zk的session相关推荐

  1. 基于ZooKeeper的分布式Session实现

    基于ZooKeeper的分布式Session实现 [转 http://blog.csdn.net/jacktan/article/details/6112806] 认识ZooKeeper ZooKee ...

  2. Java Web学习总结(20)——基于ZooKeeper的分布式session实现

    1.   认识ZooKeeper ZooKeeper-- "动物园管理员".动物园里当然有好多的动物,游客可以根据动物园提供的向导图到不同的场馆观赏各种类型的动物,而不是像走在原始 ...

  3. linux怎么看zk的版本号,zookeeper基本特性与基于Linux的ZK客户端命令行学习

    zookeeper常用命令行操作 通过 zkCli.sh 来打开zk客户端: [root@study-01 ~]# zkCli.sh [zk: localhost:2181(CONNECTED) 0] ...

  4. 内核在哪个文件夹_Apache Kafka内核深度剖析

    目前来说市面上可以选择的消息队列非常多,像activemq,rabbitmq,zeromq已经被大多数人耳熟能详,特别像activemq早期应用在企业中的总线通信,基本作为企业级IT设施解决方案中不可 ...

  5. Hbase万亿级存储性能优化总结:配置项、hdfs、zookeeper、jvm参数等

    背景 hbase主集群在生产环境已稳定运行有1年半时间,最大的单表region数已达7200多个,每天新增入库量就有百亿条,对hbase的认识经历了懵懂到熟的过程.为了应对业务数据的压力,hbase入 ...

  6. linux环境安装 kafka 0.8.2.1 jdk1.6

    文章目录 一.环境分布 二.实战 1. kafka下载 2. 解压 3. 配置 4. 编写启动脚本 5. 编写关闭脚本 6. 赋予脚本可执行权限 7. 脚本使用案例 三.Config配置 四.Cons ...

  7. ole db 访问接口 sqlncli 无法启动分布式事务_分布式锁真的安全吗?

    最近工作中遇到了一个非常棘手有趣的故障. 让我结结实实通了两宵,睡了一个周末才缓过来.不过这篇文章讲的并不是这个故障的原因, 而是修复故障所带来的衍生问题和思考. 在升级解决这些机器的过程中, 机器被 ...

  8. kafka配置文件server.properties

    Kafka为broker,producer和consumer提供了很多的配置参数. 了解并理解这些配置参数对于我们使用kafka是非常重要的. 官网配置地址: Configuration 每个kafk ...

  9. Kafka/Metaq设计思想学习笔记 转

    转载自: http://my.oschina.net/geecoodeer/blog/194829 本文没有特意区分它们之间的区别,仅仅是列出其中笔者认为好的设计思想,供后续设计参考.  目前笔者并没 ...

最新文章

  1. android 代码打开权限,android开发权限询问的示例代码
  2. 解决Putty中左边 alt+b 不工作的问题
  3. 腾讯数平精准推荐 | 横扫ICDAR 2019,斩获七项冠军
  4. 1-4dockerfile基本使用
  5. 来看看这些门户网站的变迁史 - 感受下网络发展的这段过往
  6. Java 多态(一)
  7. Cover团队在Kovan以太坊测试网部署xCOVER智能合约
  8. python进阶---pandas基本介绍
  9. 吾智商低,对于VS的char实在是不知所云
  10. 《Python数据分析实战》3 NumPy库
  11. dos批处理文件中使用vbs
  12. 游戏修改器制作教程七:注入DLL的各种姿势
  13. 决策树算法总结(下:CART决策树)
  14. 百度网盘不限速下载器 proxyee down for Mac百度网盘高速下载器
  15. android手机平板如何使用usb有线网卡
  16. 练习4闭合导线平差计算
  17. css锚点定位不准确问题
  18. 计算机启动不能马上联网,电脑开机慢不能联网
  19. WPS广告投放的优势!WPS广告投放的展现形式
  20. Visual Studio C++ 输出调试信息在调试-输出窗口

热门文章

  1. vr计算机方面的应用,AR和VR到底有什么区别,分别应用在哪些方面?
  2. Java基础321 - 如何重写equals方法
  3. SharePoint 2013 自定义扩展菜单
  4. 英国一名28岁女子晋升曾祖母
  5. 【分享】“小鹅通“在集简云平台集成应用的常见问题与解决方案
  6. 网络爬虫——票房网数据抓取及存储
  7. 无线连接服务器678,上网显示,“错误678,远程服务器~”是什么意思,怎么处理?...
  8. java精品入门-0基础第一篇
  9. Python斗鱼直播间自动发弹幕脚本
  10. opencv 文字分割