设为首页 收藏本站
查看: 972|回复: 0

[经验分享] zookeeper session tracker机制分析

[复制链接]
累计签到:8 天
连续签到:1 天
发表于 2015-9-6 07:38:04 | 显示全部楼层 |阅读模式
  说到zookeeper session管理 ,免不了要问

  •   什么是session?
  •   session id/session是如何产生的?
  •   session 信息如何存储?
  本文以session tracker线程【详见SessionTrackerImpl】的运行机制作为主线,并尝试解答一些相关问题
  
1)session基础
  
  在介绍session tracker线程之前先回答几个问题
  
1.1) 什么是session?
  
  zookeeper中session意味着一个物理连接,客户端connect成功之后,会发送一个connect型请求,此时就会有session 产生(下面会具体讲)
  
1.2)sessionid是如何产生的?
  
  在SessionTrackerImpl实例化的时候就会调用下面的函数【详见SessionTrackerImpl.initializeNextSession】


1
2
3
4
5
6


public static long initializeNextSession(long id) {
       long nextSid = 0;
       nextSid = (System.currentTimeMillis() << 24) >> 8;
       nextSid =  nextSid | (id <<56);
       return nextSid;
   }
  产生的值会存入nextSessionId属性,以后一旦有新的连接(session)产生,就会nextSessionId++
  
1.3)session是如何产生的?
  
  接到一个连接类型的请求【详见ZooKeeperServer.processConnectRequest】


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28


int sessionTimeout = connReq.getTimeOut();
        byte passwd[] = connReq.getPasswd();
        int minSessionTimeout = getMinSessionTimeout();
        if (sessionTimeout < minSessionTimeout) {
            sessionTimeout = minSessionTimeout;
        }
        int maxSessionTimeout = getMaxSessionTimeout();
        if (sessionTimeout > maxSessionTimeout) {
            sessionTimeout = maxSessionTimeout;
        }
        cnxn.setSessionTimeout(sessionTimeout);
        // We don't want to receive any packets until we are sure that the
        // session is setup
        cnxn.disableRecv();
        long sessionId = connReq.getSessionId();
        if (sessionId != 0) {
            long clientSessionId = connReq.getSessionId();
            LOG.info("Client attempting to renew session 0x"
                    + Long.toHexString(clientSessionId)
                    + " at " + cnxn.getRemoteSocketAddress());
            serverCnxnFactory.closeSession(sessionId);
            cnxn.setSessionId(sessionId);
            reopenSession(cnxn, sessionId, passwd, sessionTimeout);
        } else {
            LOG.info("Client attempting to establish new session at "
                    + cnxn.getRemoteSocketAddress());
            createSession(cnxn, passwd, sessionTimeout);
        }
  
1.3.1)确定session的timeout和id
  【详见SessionTrackerImpl.createSession】
  


1
2
3
4


synchronized public long createSession(int sessionTimeout) {
        addSession(nextSessionId, sessionTimeout);
        return nextSessionId++;
    }
  可见产生session需要两个元素,一个是sessionid,一个是timeout

  •   timeout由客户端确定,但必须在服务器规定的最大的timeout(ticktime*20)和最小的timeout(ticktime*2)之间
  •   如果客户端没有指定sessionid,那么就会产生一个新的session【详见ZooKeeperServer.createSession】,否则会reopen【详见ZooKeeperServer.reopenSession】
  •   sessionid的产生上面解释过了
1.3.2)实例化session及相关关系存放
  【详见SessionTrackerImpl.addSession】


1
2
3
4
5
6
7
8
9
10


sessionsWithTimeout.put(id, sessionTimeout);
        if (sessionsById.get(id) == null) {
            SessionImpl s = new SessionImpl(id, sessionTimeout, 0);
            sessionsById.put(id, s);
            if (LOG.isTraceEnabled()) {
                ZooTrace.logTraceMessage(LOG, ZooTrace.SESSION_TRACE_MASK,
                        "SessionTrackerImpl --- Adding session 0x"
                        + Long.toHexString(id) + " " + sessionTimeout);
            }
        }


  •   一个重要的数据结构sessionsWithTimeout存放sessionid和timeout的映射
  •   另一个重要的数据结构sessionsById存放sessionid和SessionImpl实例的映射
1.3.3)确定session实例的tickTime及sessionSets关系维护
  【详见SessionTrackerImpl.touchSession】
  
  


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16


long expireTime = roundToInterval(System.currentTimeMillis() + timeout);
        if (s.tickTime >= expireTime) {
            // Nothing needs to be done
            return true;
        }
        SessionSet set = sessionSets.get(s.tickTime);
        if (set != null) {
            set.sessions.remove(s);
        }
        s.tickTime = expireTime;
        set = sessionSets.get(s.tickTime);
        if (set == null) {
            set = new SessionSet();
            sessionSets.put(expireTime, set);
        }
        set.sessions.add(s);
  

  •   根据当前时间和timeout计算本session 的expireTime即tickTime
  •   一个重要的数据结构sessionSets 存放过期时间和一组session实例(相同过期时间)的映射的建立及维护
  •   session实例的tickTime的确定
  
  
2)session tracker线程的机制
  
  在zookeeper服务体系中,专门有一个线程(session tracker)维护session【详见SessionTrackerImpl.run】,重要代码如下


1
2
3
4
5
6
7
8
9
10
11
12
13
14


currentTime = System.currentTimeMillis();
if (nextExpirationTime > currentTime) {
    this.wait(nextExpirationTime - currentTime);
    continue;
}
SessionSet set;
set = sessionSets.remove(nextExpirationTime);
if (set != null) {
    for (SessionImpl s : set.sessions) {
        sessionsById.remove(s.sessionId);
        expirer.expire(s);
    }
}
nextExpirationTime += expirationInterval;
  
  可见SessionTrackerImpl这个线程会一直轮询的清除过期session

  •   每次轮询都会比较currentTime和nextExpirationTime,如果还未到nextExpirationTime,就等,否则往下走
  •   将sessionSets中的以nextExpirationTime为key的那组session移出
  •   遍历session,从sessionsById移除session,并调用相关的过期处理(下面会讲)
  •   调整下载比较的时间,即nextExpirationTime += expirationInterval;
  
3) session维护相关问题
  
3.1)清除session如何实现?
  【详见ZooKeeperServer.close】


1
2
3


private void close(long sessionId) {
       submitRequest(null, sessionId, OpCode.closeSession, 0, null, null);
   }
3.1.1)构造一个Request实例
3.1.2)调用PrepRequestProcessor.processRequest放入submittedRequests队列
3.1.3)PrepRequestProcessor线程的处理


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34


request.hdr = new TxnHeader(request.sessionId, request.cxid, zxid,
                            zks.getTime(), type);
                                                   
switch (type) {
                                                   
    //省略N行代码......
                                                   
    case OpCode.closeSession:
        // We don't want to do this check since the session expiration thread
        // queues up this operation without being the session owner.
        // this request is the last of the session so it should be ok
        //zks.sessionTracker.checkSession(request.sessionId, request.getOwner());
        HashSet<String> es = zks.getZKDatabase()
                .getEphemerals(request.sessionId);
        synchronized (zks.outstandingChanges) {
            for (ChangeRecord c : zks.outstandingChanges) {
                if (c.stat == null) {
                    // Doing a delete
                    es.remove(c.path);
                } else if (c.stat.getEphemeralOwner() == request.sessionId) {
                    es.add(c.path);
                }
            }
            for (String path2Delete : es) {
                addChangeRecord(new ChangeRecord(request.hdr.getZxid(),
                        path2Delete, null, 0, null));
            }
                                                   
            zks.sessionTracker.setSessionClosing(request.sessionId);
        }
                                                   
        LOG.info("Processed session termination for sessionid: 0x"
                + Long.toHexString(request.sessionId));
        break;
  
  



      •   设置request.hdr,这个很重要,

        •   在FinalRequestProcessor.processRequest会有相应的处理





1
2
3
4
5
6


if (request.hdr != null) {
              TxnHeader hdr = request.hdr;
              Record txn = request.txn;
   
              rc = zks.processTxn(hdr, txn);
           }
  ​


    •   一旦某个session关闭,与session相关的EPHEMERAL类型的节点都得清除
    •   并且通过调用sessionTracker.setSessionClosing将session设置为关闭,使得后续此session上的请求无效

3.1.4)SessionTrackerImpl相关数据结构的清理
  【详见SessionTrackerImpl.removeSession】


1
2
3
4
5
6
7
8
9
10
11
12


synchronized public void removeSession(long sessionId) {
    SessionImpl s = sessionsById.remove(sessionId);
    sessionsWithTimeout.remove(sessionId);
    if (LOG.isTraceEnabled()) {
        ZooTrace.logTraceMessage(LOG, ZooTrace.SESSION_TRACE_MASK,
                "SessionTrackerImpl --- Removing session 0x"
                + Long.toHexString(sessionId));
    }
    if (s != null) {
        sessionSets.get(s.tickTime).sessions.remove(s);
    }
}
  分别对sessionsById、sessionsWithTimeout、sessionSets进行处理
  
3.2)session owner咋回事?
  如果不是在集群环境,即没有LearnerHandler线程,session 的owner就是一个常量实例ServerCnxn.me
  
3.3)sessionsWithTimeout这个数据结构的用途?
  sessionsWithTimeout存放的是sessionid和timeout,此数据结构会和ZKDatabase中相通,会被持久化
  如果某个session timeout为60s,如果空闲了30s,意味着还能空闲30s,此时服务重启,那么此session的timeout又变为60s
  
3.4)touch session是干吗的?
  每次一旦该session有请求,就会touch,意味着session的过期时间变为(基本等于当前时间+timeout)
  具体算法为
  


1
2
3
4


private long roundToInterval(long time) {
        // We give a one interval grace period
        return (time / expirationInterval + 1) * expirationInterval;
    }
  time为System.currentTimeMillis() + timeout
  expirationInterval默认为ticktime
  
3.5)check session是干吗的
  基本上所有的事务型操作,都会调用用来验证当前请求的session是否关闭,owner是否正确
  
4)小结

  •   SessionTrackerImpl作为一个单独的线程专门处理过期session
  •   SessionTrackerImpl有3个重要的数据结构sessionsById、sessionSets、sessionsWithTimeout,其中sessionsWithTimeout会被持久化
  •   SessionTrackerImpl提供了几个常用的API

    •   createSession
    •   addSession
    •   touchSession
    •   removeSession
    •   checkSession
    •   setOwner
    •   dumpSessions
    •   


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-109851-1-1.html 上篇帖子: 【转载】zookeeper数据模型 下篇帖子: 谈话ZooKeeper(一个)分析ZooKeeper的Quorums机制--预防Split-Brain问题
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表