zookeeper session tracker机制分析
说到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
zookeeper session tracker机制分析的更多相关文章
- Session Timer机制分析
Session Timer机制分析 功能介绍 会话初始化协议(SIP)并没有为所建立的会话定义存活机制.尽管用户代理可以通过会话特定的机制判断会话是否超时,但是代理服务器却做不到这点.如此一来,代理服 ...
- 从session实现机制分析模拟请求验证码的可行性(转)
悲剧了,发现写完这篇blog没有配上这个格调超高的标题. 1.0问题背景 现在要实现一个带验证码网站的的自动登陆功能.验证码识别过程不再这篇文章的讨论之中.(之后有篇文章我会详细的总结验证码的识别 ...
- 分布式session共享机制分析
使用配置: 1.在pom文件中引入spring-session的jar包 <!--springsession--><dependency><groupId>org. ...
- Hadoop生态圈-Zookeeper的工作原理分析
Hadoop生态圈-Zookeeper的工作原理分析 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 无论是是Kafka集群,还是producer和consumer都依赖于Zoo ...
- 分布式协调组件Zookeeper之 选举机制与ZAB协议
Zookeeper简介: Zookeeper是什么: Zookeeper 是⼀个分布式协调服务的开源框架. 主要⽤来解决分布式集群中应⽤系统的⼀致性问题, 例如怎样避免同时操作同⼀数据造成脏读的问题. ...
- zookeeper节点Watch机制实例展示
znode以某种方式发生变化时,“观察”(watch)机制可以让客户端得到通知.可以针对ZooKeeper服务的“操作”来设置观察,该服务的其他 操作可以触发观察. 实现Watcher,复写proce ...
- Linux信号(signal) 机制分析
Linux信号(signal) 机制分析 [摘要]本文分析了Linux内核对于信号的实现机制和应用层的相关处理.首先介绍了软中断信号的本质及信号的两种不同分类方法尤其是不可靠信号的原理.接着分析了内核 ...
- ZooKeeper监听机制
前言:Zookeeper的监听机制很多人都踩过坑,感觉实现了watcher 接口,后面节点的变化都会一一推送过来,然而并非如此. Watch机制官方声明:一个Watch事件是一个一次性的触发器,当被设 ...
- 【Zookeeper】源码分析目录
Zookeeper源码分析目录如下 1. [Zookeeper]源码分析之序列化 2. [Zookeeper]源码分析之持久化(一)之FileTxnLog 3. [Zookeeper]源码分析之持久化 ...
随机推荐
- 多个mysql增加多个服务
//mysql安装目录 mysqld --install mysqld --remove mysql5.5 mysqld --remove mysql5.5 C:\Program Files\MySQ ...
- HDU 3555 数位dp入门
开始想用dp[i][j]来记录第i位j开头含有49的数的个数 但是init后并不知道如何进行cal 想了想可以用不要62的思想 当作不要49来做 然后减一下 就好 看网上的代码 不要62和这道题用的d ...
- Subset sum problem
https://en.wikipedia.org/wiki/Subset_sum_problem In computer science, the subset sum problem is an i ...
- Delphi下使用MapWinGIS控件打开GIS图层
unit Unit3; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System ...
- 【转】C# HttpWebRequest\HttpWebResponse\WebClient发送请求解析json数据
http://blog.csdn.net/kingcruel/article/details/44036871 版权声明:本文为博主原创文章,未经博主允许不得转载. ================= ...
- arch框架人员、组织说明
目前ERP辅助系统集成了三大模块功能,分别是财务辅助.物理辅助.报账平台. 财务辅助模块人员在ARCH_USER 表中进行管理,通过单独的[用户映射功能]将ARCH系统用户和ERP用户进行关联,关联信 ...
- 【译】Android系统架构
让我们来快速预览一下整个android系统的架构.从下面的图中我们可以发现,这个架构分为几个不同的层,底层为上一层提供服务. Linux Kernel android系统建立在一个坚固的基石上:Li ...
- RequestContextListener有什么用
问题: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request att ...
- 【Android开发学习笔记】【第二课】Activity学习
什么是Activity,就是我们所看到的 需要理解以下四句话: 1.一个Activity就是一个类,并且这个类需要集成Activity: 2.需要重写OnCreat方法 3.每个Activity都需要 ...
- JQuery中html、append、appendTo、after、insertAfter、before、insertBefore、empty、remove的使用
html方法,给元素添加html代码或者清空html代码(参数为空字符串): append向元素的末尾添加html代码: appendTo这个方法跟append方法的很像,只是要添加的html代码的目 ...