基本属性
- sessionId:会话ID,特点是全局唯一,保证sessionId全局唯一的基本思想是机器标识+随机数(时间戳),机器标识区分集群中不同的机器,同一台机器内的session可以用随机数、内存地址、计数器等多种手段来区分,一般会结合业务场景赋予一定的业务语义来使用;
- timeout:会话超时时间(时间段),当会话超时失效后,与会话绑定的数据、其创建的所有临时节点和watcher都会被删除;
- tickTime:会话下次超时时间(时间点),便于会话的分桶管理和超时检测清理;
- owner:会话拥有者,ZK服务器在收到客户端的请求后会首先检查session的owner,如果owner不是当前服务器的话,会给客户端返回SessionMovedException;
全局唯一ID创建
- 每台机器初始化全局唯一的基础SessionId;
- 每次创建Session时依次递增;
public static long initializeNextSession(long id) {
long nextSid = 0;
nextSid = (System.currentTimeMillis() << 24) >> 8;
nextSid = nextSid | (id <<56);
return nextSid;
}
synchronized public long createSession(int sessionTimeout) {
addSession(nextSessionId, sessionTimeout);
return nextSessionId++;
}
生命周期
- 创建:客户端与ZK集群连接建立后,服务端就会创建session;
- 保持(有效性):客户端发送心跳或者读写请求都能保持session的有效性;
- 失效(超时过期):若指定时间内不再接受心跳或读写请求,则ZK集群认为session失效;
Session管理
问题:实际生产环境中,ZK集群中的Session数量会非常多,ZK如何高效管理?
思想: 批处理,将超时时间接近的Session集中到一起,统一处理;
分桶策略:首先,计算出每个session理论上的超时时间;然后按照公式进行调整,最终将超时时间相近的session调整成相同的,然后存储在同一个桶里;
会话激活:只要客户端有请求(心跳或者业务请求)发送到服务端,客户端对应的session都会被激活,重新计算超时时间,迁移到新的桶中;
会话清理: ZK集群的master机器会有一个线程定时地检查session是否超时,如果超时则将session置为无效,将其绑定的数据、创建的所有临时节点及watcher删除;