• zookeeper源码分析之六session机制


    zookeeper中session意味着一个物理连接,客户端连接服务器成功之后,会发送一个连接型请求,此时就会有session 产生。

    session由sessionTracker产生的,sessionTracker的实现有SessionTrackerImpl,LocalSessionTracker,LeaderSessionTracker(leader),LearnerSessionTracker(follow and oberser)四种实现。它们的分支由各自的zookeeperServer.startup()开始。

    1.sessionTrackerImpl

    标准zookeeperServer的实现

        public synchronized void startup() {
            if (sessionTracker == null) {
                createSessionTracker();
            }
            startSessionTracker();
            setupRequestProcessors();
    
            registerJMX();
    
            state = State.RUNNING;
            notifyAll();
        }

    其实现由sessionTrackerImpl来实现,其官方说明

    /**
    * This is a full featured SessionTracker. It tracks session in grouped by tick
    * interval. It always rounds up the tick interval to provide a sort of grace
    * period. Sessions are thus expired in batches made up of sessions that expire
    * in a given interval.
    */

        protected void createSessionTracker() {
            sessionTracker = new SessionTrackerImpl(this, zkDb.getSessionWithTimeOuts(),
                    tickTime, 1, getZooKeeperServerListener());
        }
    
        protected void startSessionTracker() {
            ((SessionTrackerImpl)sessionTracker).start();
        }

    sessionTrackerImpl是一个线程,其run方法是真实逻辑:

        @Override
        public void run() {
            try {
                while (running) {
                    long waitTime = sessionExpiryQueue.getWaitTime();
                    if (waitTime > 0) {
                        Thread.sleep(waitTime);
                        continue;
                    }
    
                    for (SessionImpl s : sessionExpiryQueue.poll()) {
                        setSessionClosing(s.sessionId);
                        expirer.expire(s);
                    }
                }
            } catch (InterruptedException e) {
                handleException(this.getName(), e);
            }
            LOG.info("SessionTrackerImpl exited loop!");
        }

    sessionTrackerImpl实现了session的各种操作:创建session,检测session,删除session等。我们以增加session为例,看一下session机制:

        public long createSession(int sessionTimeout) {
            long sessionId = nextSessionId.getAndIncrement();
            addSession(sessionId, sessionTimeout);
            return sessionId;
        }
     public synchronized boolean addSession(long id, int sessionTimeout) {
            sessionsWithTimeout.put(id, sessionTimeout);
    
            boolean added = false;
    
            SessionImpl session = sessionsById.get(id);
            if (session == null){
                session = new SessionImpl(id, sessionTimeout);
            }
    
            // findbugs2.0.3 complains about get after put.
            // long term strategy would be use computeIfAbsent after JDK 1.8
            SessionImpl existedSession = sessionsById.putIfAbsent(id, session);
    
            if (existedSession != null) {
                session = existedSession;
            } else {
                added = true;
                LOG.debug("Adding session 0x" + Long.toHexString(id));
            }
    
            if (LOG.isTraceEnabled()) {
                String actionStr = added ? "Adding" : "Existing";
                ZooTrace.logTraceMessage(LOG, ZooTrace.SESSION_TRACE_MASK,
                        "SessionTrackerImpl --- " + actionStr + " session 0x"
                        + Long.toHexString(id) + " " + sessionTimeout);
            }
    
            updateSessionExpiry(session, sessionTimeout);
            return added;
        }

    上文中出现了一个nextSessionId,看一下其的生成方式:

        /**
         * Generates an initial sessionId. High order byte is serverId, next 5
         * 5 bytes are from timestamp, and low order 2 bytes are 0s.
         */
        public static long initializeNextSession(long id) {
            long nextSid;
            nextSid = (Time.currentElapsedTime() << 24) >>> 8;
            nextSid =  nextSid | (id <<56);
            return nextSid;
        }

    创建sessionImpl

      红色代码所示。

    更新过期时间并记录

        private void updateSessionExpiry(SessionImpl s, int timeout) {
            logTraceTouchSession(s.sessionId, timeout, "");
            sessionExpiryQueue.update(s, timeout);
        }
    
        private void logTraceTouchSession(long sessionId, int timeout, String sessionStatus){
            if (!LOG.isTraceEnabled())
                return;
    
            String msg = MessageFormat.format(
                    "SessionTrackerImpl --- Touch {0}session: 0x{1} with timeout {2}",
                    sessionStatus, Long.toHexString(sessionId), Integer.toString(timeout));
    
            ZooTrace.logTraceMessage(LOG, ZooTrace.CLIENT_PING_TRACE_MASK, msg);
        }

    从上面的代码可以看出,session都存放在一个sessionById的map里面,其定义为:

    protected final ConcurrentHashMap<Long, SessionImpl> sessionsById =
    new ConcurrentHashMap<Long, SessionImpl>();

    2. LeaderSessionTracker

    官方说明:

    /**
    * The leader session tracker tracks local and global sessions on the leader.
    */

    LeaderZooKeeperServer、LeaderZooKeeperServer、FollowerZooKeeperServer、ObserverZooKeeperServer均继承自QuorumZooKeeperServer,

    QuorumZooKeeperServer的startSessionTracker方法如下:

        @Override
        protected void startSessionTracker() {
            upgradeableSessionTracker = (UpgradeableSessionTracker) sessionTracker;
            upgradeableSessionTracker.start();
        }
    UpgradeableSessionTracker的实现类有两个:LeaderSessionTracker和LearnerSessionTracker,很显然,对leaderZookeeper的实现为LeaderSessionTracker,LearnerSessionTracker对应FollowerZooKeeperServer、ObserverZooKeeperServer。
    LeaderSessionTracker的构造函数为:
        public LeaderSessionTracker(SessionExpirer expirer,
                ConcurrentMap<Long, Integer> sessionsWithTimeouts,
                int tickTime, long id, boolean localSessionsEnabled,
                ZooKeeperServerListener listener) {
    
            this.globalSessionTracker = new SessionTrackerImpl(
                expirer, sessionsWithTimeouts, tickTime, id, listener);
    
            this.localSessionsEnabled = localSessionsEnabled;
            if (this.localSessionsEnabled) {
                createLocalSessionTracker(expirer, tickTime, id, listener);
            }
            serverId = id;
        }

    其分为两个sessionTracker,一个为globalSessionTracker,其实现为SessionTrackerImpl;另一个为localSessionTracker,其实现为:

        public void createLocalSessionTracker(SessionExpirer expirer,
                int tickTime, long id, ZooKeeperServerListener listener) {
            this.localSessionsWithTimeouts =
                new ConcurrentHashMap<Long, Integer>();
            this.localSessionTracker = new LocalSessionTracker(
                expirer, this.localSessionsWithTimeouts, tickTime, id, listener);
        }
    LeaderSessionTracker启动时同时启动global和local:
        public void start() {
            globalSessionTracker.start();
            if (localSessionTracker != null) {
                localSessionTracker.start();
            }
        }

    创建session的过程:

        public long createSession(int sessionTimeout) {
            if (localSessionsEnabled) {
                return localSessionTracker.createSession(sessionTimeout);
            }
            return globalSessionTracker.createSession(sessionTimeout);
        }
    globalSessionTracker的创建session上面已经论述,且看localSessionTracker的生成session,进一步代码发现LocalSessionTracker继承了SessionTrackerImpl,没有重写其创建session方法,即global和local创建session的方法相同。

    3. LearnerSessionTracker

    官方说明:

    /**
    * The learner session tracker is used by learners (followers and observers) to
    * track zookeeper sessions which may or may not be echoed to the leader. When
    * a new session is created it is saved locally in a wrapped
    * LocalSessionTracker. It can subsequently be upgraded to a global session
    * as required. If an upgrade is requested the session is removed from local
    * collections while keeping the same session ID. It is up to the caller to
    * queue a session creation request for the leader.
    * A secondary function of the learner session tracker is to remember sessions
    * which have been touched in this service. This information is passed along
    * to the leader with a ping.
    */


    其构造方法是:
        public LearnerSessionTracker(SessionExpirer expirer,
                ConcurrentMap<Long, Integer> sessionsWithTimeouts,
                int tickTime, long id, boolean localSessionsEnabled,
                ZooKeeperServerListener listener) {
            this.expirer = expirer;
            this.touchTable.set(new ConcurrentHashMap<Long, Integer>());
            this.globalSessionsWithTimeouts = sessionsWithTimeouts;
            this.serverId = id;
            nextSessionId.set(SessionTrackerImpl.initializeNextSession(serverId));
    
            this.localSessionsEnabled = localSessionsEnabled;
            if (this.localSessionsEnabled) {
                createLocalSessionTracker(expirer, tickTime, id, listener);
            }
        }

    启动时只启动了localSessionTracker:

        public void start() {
            if (localSessionTracker != null) {
                localSessionTracker.start();
            }
        }

    创建session时也仅仅由localSessionTracker生成:

        public long createSession(int sessionTimeout) {
            if (localSessionsEnabled) {
                return localSessionTracker.createSession(sessionTimeout);
            }
            return nextSessionId.getAndIncrement();
        }

     4 小结

        根据服务器角色不同,ZooKeeperServer,LeaderZooKeeperServer,FollowerZooKeeperServer,ObserverZooKeeperServer分别代表单机服务器,集群leader服务器,集群Follower服务器,集群observer服务器,它们的sessionTracker实现是不同的。ZookeeperServer的对应sessionTracker实现是SessionTrackerImpl;LeaderZooKeeperServer的对应sessionTracker实现是LeaderSessionTracker,FollowerZooKeeperServer,ObserverZooKeeperServer的对应sessionTracker实现是LearnerSessionTracker。

      有可以分为globalSessionTracker和LocalSessionTracker,其中单机只有一个标准的SessionTrackerImpl,集群leader开启globalSessionTracker和LocalSessionTracker,follower和observer只开启LocalSessionTracker。globalSessionTracker由SessionTrackerImpl实现,LocalSessionTracker继承并扩展了SessionTrackerImpl。








     
  • 相关阅读:
    Fetch的使用
    if判断中的true和false
    分布式、微服务和集群的初步了解
    关于视频的知识点
    ajax请求
    jq的遍历关系元素方法集合
    docker安装Mysql
    设计模式系列之七大原则之——开闭原则
    设计模式系列之七大原则之——里式替换原则
    设计模式系列之七大原则之——依赖倒转原则
  • 原文地址:https://www.cnblogs.com/davidwang456/p/5009659.html
Copyright © 2020-2023  润新知