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。