ZooKeeper个人笔记Session管理

Session

1.sessionId  <机器的SID,当前时间>生成一个sessionId,这是全局唯一的。

2.TimeOut 会话的超时时间,注意,这个值和客户端ZooKeeper对象指定的超时不一定相同

3.TickTime

4.isClosing 当SessionTracker检测到会话已经失效了,就会将这个会话的isClosing标记为true,之后这个会话将不在处理任何新的请求

SessionTracker

SessionTracker负责管理Session的整个会话生命周期。

SessionTracker的创建

如何管理多个session?

ExpireTime1 [session,session,session]

ExpireTime2 [session,session,session]

新创建的Session,其expireTime=curTime+SessionTimeout

leader服务器每隔expirationInterval时间就进行会话超时检查。

客户端向服务器发送请求,服务器就进行一次会话激活

客户端如果在sessionTimeout/3时间内,没有向服务器发送过任何请求,就主动发送一个PING请求,服务器收到

该请求后激活会话。

创建SessionTracker

在org.apache.zookeeper.server.ZooKeeperServer的startup方法中,会创建SessionTracker,然后启动它。

    public void startup() {
if (sessionTracker == null) {
createSessionTracker();
}
//SessionTrackerImpl继承了Thread,因此实际上他也是个线程,这里就是调用start方法执行线程。
startSessionTracker();
setupRequestProcessors(); registerJMX(); synchronized (this) {
running = true;
notifyAll();
}
}
    protected void createSessionTracker() {
sessionTracker = new SessionTrackerImpl(this, zkDb.getSessionWithTimeOuts(),
tickTime, 1);
}

激活会话

 synchronized public boolean touchSession(long sessionId, int timeout) {
if (LOG.isTraceEnabled()) {
ZooTrace.logTraceMessage(LOG,
ZooTrace.CLIENT_PING_TRACE_MASK,
"SessionTrackerImpl --- Touch session: 0x"
+ Long.toHexString(sessionId) + " with timeout " + timeout);
}
//获取Session
SessionImpl s = sessionsById.get(sessionId);
// Return false, if the session doesn't exists or marked as closing
if (s == null || s.isClosing()) {
return false;
}
//计算超时时间点
long expireTime = roundToInterval(System.currentTimeMillis() + timeout);

//表明没有超时
if (s.tickTime >= expireTime) {
// Nothing needs to be done
return true;
}
//将Session从旧的set移动到新的set中
//首先取出tickTime对应的set,然后从set中移除掉Session
SessionSet set = sessionSets.get(s.tickTime);
if (set != null) {
set.sessions.remove(s);
}
//迁移到新的set中
s.tickTime = expireTime;
set = sessionSets.get(s.tickTime);
if (set == null) {
set = new SessionSet();
sessionSets.put(expireTime, set);
}
set.sessions.add(s);
return true;
}

会话超时检查

   @Override
synchronized public void run() {
try {
while (running) {
currentTime = System.currentTimeMillis();
//如果还未超时
if (nextExpirationTime > currentTime) {
this.wait(nextExpirationTime - currentTime);
continue;
}

SessionSet set;
//已经超时了,很粗暴的直接从sessionSets中移走过期的session,这里做的真是太棒了
set = sessionSets.remove(nextExpirationTime);
if (set != null) {
//将每一个过期的session标记为close。
for (SessionImpl s : set.sessions) {
setSessionClosing(s.sessionId);
//注意这里哦,很重要的。这里就是调用ZooKeeperServer.expire来关闭session
expirer.expire(s);
}
}
//计算新的过期时间
nextExpirationTime += expirationInterval;
}
} catch (InterruptedException e) {
LOG.error("Unexpected interruption", e);
}
LOG.info("SessionTrackerImpl exited loop!");
}
    public void expire(Session session) {
long sessionId = session.getSessionId();
LOG.info("Expiring session 0x" + Long.toHexString(sessionId)
+ ", timeout of " + session.getTimeout() + "ms exceeded");
//因为会话已经超时了,所以关闭它
close(sessionId);
}
  private void close(long sessionId) {
submitRequest(null, sessionId, OpCode.closeSession, 0, null, null);
}

清理会话

找出这个session创建的所有临时节点,就是去ZooKeeper内存数据库中,根据sesionID来获取这个session创建的所有的临时节点信息,对每一个节点创建节点删除请求,从内存数据库中移除该会话的临时节点。

将session从SessionTrackerImpl中移除

关闭ServerCnxn。

KeeperException.ConnectionLoseException

客户端捕获到这种异常,只需要简单的等待org.apache.zookeeper.ZooKeeper自动重新连接上一个ZooKeeper机器即可,当重新连上了之后,客户端会受到Sync_Connected通知。

SESSION_EXPIRED

由于客户端在会话超时时间内没有向服务器发送PING,服务器认为会话已经过期,然后就会将其标记为失效了。如果之后客户端重新连接上了某一个机器,那么就会出现会话过期异常了。在这种情况下,只能创建一个新的ZooKeeper对象,建立一个新的会话了。

SessionMovedException

上一篇:HAproxy功能配置


下一篇:2018 年终总结 & 2019 年度计划