主要讲述zookeeper客户端的的会话创建的过程,会话创建后服务端对会话是如何管理的。会话创建后,客户端发起读写操作的一整个流程是什么样的呢?

Zookeeper客户端和服务端的读写操作、Watcher通知机制等都是基于会话来实现的,会话本质上是一个TCP的长连接。
长连接的一个好处是创建连接后可以一直传输数据,不像短连接那样传输完数据后就关闭连接,因为网络中不同节点使用TCP协议通过SOCKET进行通信,首先需要3次握手建立连接,数据传输,4次握手断开连接,因此如果频繁的创建、关闭,是很耗费系统资源的。
短连接 : 连接->传输数据->关闭连接
长连接: 连接->传输数据->保持连接 -> 传输数据-> 。。。 ->关闭连接。
考虑到zookeeper的连接特性,一个客户端只会和你配置中的zookeeper server集群中的一台节点建立连接,可能是leader或者follower节点,只需要一个TCP长连接就足以应对,因选择一个TCP长连接,不失为一种最好的方案。

会话是由Zookeeper服务端进行管理的,一个服务端可以有多个Session,那么这些session是如何进行管理的呢?什么时候移除呢?
session属性
首先我们先看下会话Session实体的四个重要属性。
sessionID 。 会话ID,唯一标识一个会话,每次客户端创建新的会话时,Zookeeper都会为其分配一个全局唯一的sessionID。
timeOut。会话超时时间,客户端在构造Zookeeper实例时,会配置sessionTimeout参数用于指定会话的超时时间,Zookeeper客户端向服务端发送这个超时时间后,服务端会根据自己的超时时间限制最终确定会话的超时时间。
Expiration Time。下次会话超时的时间点,是时间轴上的一个绝对时间点,为了便于Zookeeper对会话实行"分桶策略"管理,同时为了高效低耗地实现会话的超时检查与清理,Zookeeper会为每个会话标记一个下次会话超时时间点,其值大致等于当前时间加上TimeOut。
isClosing。标记一个会话是否已经被关闭,当服务端检测到会话已经超时失效时,会将该会话的isClosing标记为"已关闭",这样就能确保不再处理来自该会话的心情求了。
分桶策略
Zookeeper的会话管理采用分桶策略(将类似的会话放在同一区块中进行管理)进行管理。

Zookeeper服务端基于ExpirationTime过期时间点作为维度维护着一个个“桶”,将相似ExpirationTime的session放在一块,那么在运行期间Zookeeper服务器进行会话超时检查时,只要扫描对应的桶进行检查就行,避免了遍历全部Sesssion, 提高效率。
每个会话的ExpirationTime的计算时间如下:
ExpirationTime = ((CurrentTime + SessionTimeOut) / ExpirationInterval + 1) * ExpirationInterval
Session 激活
ExpirationTime 会话过期时间点并不是一直不变,就想像程我们web应用中的session,每次请求访问都会重新刷新过期时间点,zookeeper也需要重新更新会话的ExpirationTime,这一个过程叫做Session激活。
下面两种方式都会重新触发Session 激活:

Session激活流程如上图,大致分为4步:
Zookeeper服务端有专门的会话超时间检查线程,逐个检查会话桶中的会话,针对没有激活已经过期的会话进行删除临时节点,清理会话等操作。

Zookeeper读过程相对简单,客户端Client和server端建立连接后,这个server节点无论时Leader 还是 Follower ,Client发出读请求之后,都会直接返回结果。
但是,Client读操作不能保证读取到的时最新的数据,有可能是旧数据, 如下图的场景。

官网也给出了解释:



主要讲解了Zookeeper客户端和服务端的一些交互过程,包括会话创建和管理,以及客户端读写的整个流程。欢迎评论区讨论