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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM