栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【Zookeeper】Session会话机制及实现

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Zookeeper】Session会话机制及实现

目录
  • Session结构
  • 会话创建
  • 会话管理
    • 会话清理
    • 会话激活
    • 会话重连

Session结构

Zookeeper在执行任何请求之前,都需要在客户端和服务端之间先建立Session,如客户端的请求顺序执行、watcher的通知机制等。所谓Session,就是客户端与服务端之间创建的一个 TCP长链接 。

Session结构

  • SessionId:会话id
  • TimeOut:会话从新建到关闭的时长,由Zookeeper服务端管理
  • ExpirationTime:创建时间+TimeOut。是一个绝对时间。
  • IsClosing:会话的关闭状态

Session状态

  • Connecting:正在连接,客户端与服务端建立连接时的状态
  • Connected:已连接,客户端与服务端完成连接
  • ReConnecting:正在重连,客户端与服务端断开连接,Session重连机制发起重连时重新连接的状态
  • ReConnected:已经重连
  • Close:连接关闭

成员变量

// sessionId与Session的映射
protected final ConcurrentHashMap 
        sessionsById = new ConcurrentHashMap();
//过期策略
private final ExpiryQueue sessionExpiryQueue;
//标志session的超时时间
private final ConcurrentMap sessionsWithTimeout;
会话创建

首先关注客户端与服务端相关的线程及队列:

客户端

  • 网络连接器:ClientCnxn
  • 关键队列
    • outgoingQueue:客户端请求发送队列
    • pendingQueue:客户端等待服务端响应的等待队列
  • 关键线程
    • SendThread:管理客户端与服务端所有的网络IO
      • ClientCnxnSocket:底层IO处理器
    • EventThread:用于客户端事件处理
      • 队列:waitingEvents,待处理事件队列

服务端

  • 会话管理器:SessionTracker。负责会话的创建、管理、清理等

会话创建流程

  1. 客户端选择服务器地址发起连接
    SendThread线程随机选择一个我们提供的zookeeper服务器地址,委托给ClientCnxnSocket去创建连接。

  2. 创建TCP连接
    ClientCnxnSocket和服务器之间建立一个TCP长连接

  3. 发送请求
    构造ConnectRequest请求、并转换为Packet对象,放到outgoingQueue队列中。ClientCnxnSocket将Packet从队列中取出,序列化后发送给服务端。

  4. 服务器处理请求
    服务端为此客户端分配一个SessionId,并发送响应

  5. 客户端接收响应
    ClientCnxnSocket接收服务端的响应,判断当前客户端的状态是否已变化:如果尚未完成初始化,说明这是一个创建会话的请求

  6. 更新客户端状态
    客户端从中读取被分配的SessionId,通知SendThread更新Client会话参数、更新客户端的状态

  7. 生成事件
    为了让上层应用感知到Session创建成功,SendThread会生成一个事件并放入EventThread,EventWatcher收到事件后会查询ZKWatcherManager对应的Watcher,然后放入waiting队列。

  8. 处理事件
    EventWatcher从waiting中取出watcher对象,分别调用其process方法。

分配SessionId:

public static long initializeNextSessionId(long id) {
    long nextSid;
    nextSid = (Time.currentElapsedTime() << 24) >>> 8;
    nextSid = nextSid | (id << 56);
    if (nextSid == EphemeralType.CONTAINER_EPHEMERAL_OWNER) {
        ++nextSid;  // this is an unlikely edge case, but check it just in case
    }
    return nextSid;
}

前7位确定了所在的机器,后57位使用当前时间的毫秒表示进行随机。

会话管理 会话清理
  • 分桶策略

将类似的会话放在同一区块中进行管理,而Zookeeper区分这些Session的维度,就是ExpirationTime。

如此区分的原因:Zookeeper服务端在运行时会对会话进行超时检查,这样区分可以避免对全部的Session进行扫描。

ExpirationTime 的计算方式:

// 1. 先计算当前Session过期的具体时间
ExpirationTime = CurrentTime + SessionTimeout;
// 2. ExpirationInterval:Zk的检查频率(默认2s)。
// 将ExpirationTime映射为ExpirationInterval的倍数。
ExpirationTime = (ExpirationTime / ExpirationInterval + 1) * ExpirationInterval

服务端检查到一个Session已经超时后:

  1. 标记此Session状态为已关闭,这样在关闭期间也不能处理该客户端的请求
  2. 发起关闭会话的请求,收集需要清理的临时节点。一旦某个会话失效后,与该会话相关的临时节点都需要被清除。
    临时节点的生命周期为Session,即在一个连接session有效期内临时节点是活跃的,当连接断开后session自然会过期,那么临时节点就会被删除
  3. 针对这些节点,创建节点删除事务,从内存数据库中删除
  4. 从SessionTracer中移除此Session,并关闭此Session对应的NIOServerCnxn
会话激活

客户端与服务端完成连接之后,生成的过期时间并不是一直不变的,而是会随着客户端与服务端的交互更新。也就是说,客户端会通过发送请求或者心跳来保持会话的有效性。

过期时间的更新,就意味着Session需要在桶之间迁移。

  1. 客户端向服务端发送请求,都会触发一次激活。

  2. 客户端一直没有请求,在TimeOut的三分之一时间,发送一次Ping,用来续约。

  3. 客户端直接断开,那么TimeOut时间到期后,当前Session会被服务端扫描到并清理。

会话重连

因为在客户端存在心跳机制不断地进行激活,所以一般情况下会话是一直有效的。但是当客户端与服务端之间的连接断开后,用户在客户端可能主要会看到两类异常:

  • CONNECTION_LOSS:连接断开
    当客户端与服务端之间网络断开时,客户端将会进行反复尝试重连集群中其他的服务器,直到连接上Zookeeper服务端中的一台机器

  • SESSION_EXPIRED:会话过期
    客户端和服务器连接断开之后,由于重连期间耗时过长,超出了sessionTimeout还没有成功重连,那么服务器开始进行会话清理。但是客户端此时并不能感知会话已失效。
    一直等到客户端重新连接上服务器,服务器会告知客户端该会话已经失效(SESSION_EXPIRED),然后再关闭当前会话。

所以重连之后的客户端可能有两种状态:

  • Connected:会话超时时间之内,重连成功
  • Expired:重连超出了会话超时时间
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/270516.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号