客户端与服务端之间的连接是基于 TCP 长连接,client 端连接 server 端默认的 2181 端口,也就是 session 会话。
从第一次连接建立开始,客户端开始会话的生命周期,客户端向服务端的ping包请求,每个会话都可以设置一个超时时间。
本篇文章从ZK Session来对ZK有一个更深的认知。
Session
在Zookeeper中,Session是个很重要的概念之一,客户端与服务端之间的任何交互操作都和Session息息相关,其中包含zookeeper的临时节点的生命周期、客户端请求执行以及Watcher通知机制等。
Session常用属性
sessionID: 会话ID,用来唯一标识一个会话,每次客户端创建会话的时候,zookeeper 都会为其分配一个全局唯一的 sessionID。zookeeper 创建 sessionID 类 SessionTrackerImpl 中的源码。
/**
* Generates an initial sessionId. High order 1 byte is serverId, next
* 5 bytes are from timestamp, and low order 2 bytes are 0s.
* Use ">>> 8", not ">> 8" to make sure that the high order 1 byte is entirely up to the server Id(@see ZOOKEEPER-1622).
* @param id server Id
* @return the Session Id
*/
public static long initializeNextSessionId(long id) {
long nextSid;
nextSid = (Time.currentElapsedTime() << 24) >>> 8;
nextSid = nextSid | (id << 56);
if (nextSid == EphemeralType.CONTAINER_EPHEMERAL_OWNER) {
++nextSid; // this is an unlikely edge case, but check it just in case
}
return nextSid;
}
Timeout:会话超时时间。客户端在构造 Zookeeper 实例时候,向服务端发送配置的超时时间,server 端会根据自己的超时时间限制最终确认会话的超时时间。
TickTime:下次会话超时时间点,默认2000 毫秒。可在 zoo.cfg 配置文件中配置,便于server 端对 session 会话实行分桶策略管理。
isClosing:该属性标记一个会话是否已经被关闭,当 server 端检测到会话已经超时失效,该会话标记为"已关闭",不再处理该会话的新请求。
Session的状态
下面介绍几个重要的状态:
(1)connecting:连接中,session 一旦建立,状态就是 connecting 状态,时间很短。
(2)connected:已连接,连接成功之后的状态。
(3)closed:已关闭,发生在 session 过期,一般由于网络故障客户端重连失败,服务器宕机或者客户端主动断开。
SessionTracker
SessionTracker其中的一个实现类是SessionTrackerImpl:
SessionTracker是Zookeeper中的会话管理器,负责整个zk生命周期中会话的创建、管理和清理操作:
(1)sessionsWithTimeout:这是一个ConcurrentMap<Long,Integer>类型的数据结构,用来管理会话的超时时间,这个参数会被持久化到快照文件中去。
(2)sessionsById:是一个ConcurrentHashMap<Long,SessionImpl>类型的数据结构,用于根据sessionId来管理session实体。
Session的创建流程
客户端和服务端Socket连接建立成功后,客户端会向服务端发送一个ConnectRequest请求,服务端接收到ConnectRequest请求后,会创建SessionImpl对象,并且把SessionImpl对象放入sessionsById中(sessionById是一个Map),并且会把Session的过期时间更新到sessionExpiryQueue中,然后会在服务端内部构造一个OpCode.createSession的Request,该Request会依次经过PrepRequestProcessor、SyncRequestProcessor、FinalRequestProcessor。
(1)在PrepRequestProcessor中设置Reqeust的txn
(2)在SyncRequestProcessor对txn进行持久化(创建session的操作会持久化)
(3)在FinalRequestProcessor会对Session进行提交,其实就是把Session的ID和Timeout存到sessionsWithTimeout中去
Session的刷新流程
服务端每接收到一个请求(包括增删查改和Ping请求),都会对sessionExpiryQueue中的Session的过期时间进行刷新。
Session的过期处理流程
SessionTrackerImpl是SessionTracker的实现类,由它负责处理Session的过期时间刷新和对过期的Session进行处理。
SessionTrackerImpl是一个线程,该线程会每隔一个tickTime就去检查一下有没有Session已经过期,如果过期了,则对Session进行过期处理,构造一个closeSession的Request,交给服务端进行处理。
Session的关闭流程
对应的操作是closeSession,也会进行持久化,同时FinalRequestProcessor在执行closeSession请求时,会删除临时节点,并且把session从sessionsById、sessionsWithTimeout、sessionExpiryQueue移除掉。