乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • ZooKeeper 学习路径
  • 第1章 分布式协调与ZooKeeper概述

    • ZooKeeper 概述
  • 第2章 单机与集群搭建

    • 配置参数详解
    • 集群搭建
  • 第3章 数据模型与ZNode

    • ZNode 详解
    • 节点类型对比
    • 顺序节点
    • ACL 权限控制
  • 第4章 会话与Watcher机制

    • 会话机制
    • Watcher 机制
  • 第5章 ZAB协议与一致性保证

    • ZAB 协议
    • 一致性保证
    • 数据同步
  • 第6章 Leader选举

    • Leader 选举
  • 第7章 典型应用:分布式锁

    • 分布式锁
  • 第8章 典型应用:配置中心与命名服务

    • 配置中心
    • 命名服务
  • 第9章 客户端编程基础(Java原生API)

    • Java 原生 API 编程
  • 第10章 运维与监控

    • 四字命令
    • 监控体系
  • 第11章 面试考点与设计思想

    • 设计思想
    • 面试考点汇编

本章定位:Session 是 ZooKeeper 所有临时节点和 Watcher 的生命周期载体。理解 Session 的状态转换和超时机制,是正确使用 Ephemeral 节点和 Watcher 的前提。

定义与作用

Session 是客户端与 ZooKeeper 服务端之间的一个逻辑连接。客户端通过 TCP 连接到某个 Server,并建立 Session。核心特性:

特性说明
Session ID全局唯一 64 位标识,由 Leader 分配
Session Timeout客户端与服务器协商的超时时间
心跳维持通过 ping 请求隐性延长 Session
状态迁移CONNECTING → CONNECTED → (EXPIRED / CLOSED)
载体作用Ephemeral 节点和 Watcher 绑定到 Session

核心原理

Session 生命周期状态机

一旦 Session 过期,之前的 SessionID 作废,所有相关的 Ephemeral 节点被服务端删除,所有 Watcher 被清除。客户端即使重新连接也只能建立全新的 Session。

心跳与超时机制

客户端和服务端协商 Session Timeout。客户端发送期望值,服务端将其约束在 [minSessionTimeout, maxSessionTimeout] 范围内(默认 min=2tickTime, max=20tickTime)。

本地会话(Local Session)—— 3.5.0+

ZooKeeper 3.5.0 引入本地会话(Local Session),专门应对海量客户端连接场景。传统全局会话(Global Session)要求 Leader 为每个 Session 分配 Session ID 并经过 Quorum 确认(Commit),当客户端数量达到数万级别时,这种"全集群共识"的开销成为瓶颈。

本地会话的核心思想:将 Session 管理下沉到与其建立连接的那个 Server(通常为 Observer),不经过 Leader 和 Quorum 共识,大幅降低集群协调开销。

全局会话 vs 本地会话对比:

维度全局会话 (Global Session)本地会话 (Local Session)
Session ID 分配Leader 分配并 Commit本地 Server 直接分配
是否需要 Quorum 确认是(过半 Follower ACK)否
能否创建临时节点可以不可以
能否注册 Watcher可以可以(本地维护)
是否持久化到事务日志是否
故障转移行为自动迁移到其他 Server直接过期(不可迁移)
适用场景普通客户端(需要 Ephemeral)海量轻量客户端 / Observer 前置

升级机制:

本地会话可通过 SessionTracker 升级为全局会话:本地 Server 内部使用 LocalSessionTracker 追踪本地会话;当客户端请求需要创建 Ephemeral 节点时,服务端自动触发升级——将 LocalSessionTracker 中的 Session 信息提交给 SessionTrackerImpl(全局),追加 Leader Commit 流程。升级后客户端获得 Ephemeral 节点能力和 Session 迁移能力。

关键易错:本地会话升级为全局会话时,超时计时器会重置。即升级前的空闲时间不计入全局 Session 的超时倒计时,新全局 Session 的超时从升级时刻重新计算。如果客户端在本地会话阶段已经空闲了很久,升级后仍需要再等 sessionTimeout 才会过期——可能导致预期外的长期存活。

配置方式:

# zoo.cfg
# 对普通端口不启用本地会话(默认全局)
# 在 Observer 行中启用 localSessionsEnabled
server.4=observer-host:2888:3888:observer;observer-host:2184

# 或在 zoo.cfg 中全局设置
localSessionsEnabled=true
localSessionsUpgradingEnabled=true

适用场景:

  • Observer 前置的 CDN / 边缘节点场景(上千个轻量客户端只需读配置)
  • 物联网设备上报心跳(不需要 Ephemeral 节点,只做健康状态上报)
  • 消息中间件的消费者/生产者注册(只读配置 + Watcher 监听)

完整示例

示例一:Session 超时与 Ephemeral 节点生命周期

场景说明:验证 Session 超时后 Ephemeral 节点自动删除。

操作前状态:正常连接,Session 存活。

# Terminal 1 —— 连接并创建临时节点
zkCli.sh -server 127.0.0.1:2181
# 自动生成 sessionTimeout = 30000

[zkshell: 0] create -e /session-test/node1 "node1-data"
Created /session-test/node1
# Terminal 2 —— 观察节点
zkCli.sh -server 127.0.0.1:2181
[zkshell: 0] ls /session-test
[node1]

模拟超时(Terminal 1 空闲 35 秒,超过 Session Timeout):

# Terminal 2 —— 会话过期后查看
[zkshell: 1] ls /session-test
[]

# 输出显示 Terminal 1 的连接状态:
WATCHER::
WatchedEvent state:Expired type:None path:null

操作后状态:

时间点Terminal 1Terminal 2 看到的 /session-test原因
创建后CONNECTED[node1]正常
~35s 后EXPIRED[]Session 超时,节点自动删除

示例二:Java API 中的 Session 管理

场景说明:通过 Java 原生 API 管理 Session 状态。

import org.apache.zookeeper.*;

public class SessionDemo {
    public static void main(String[] args) throws Exception {
        // 创建 ZooKeeper 实例,指定 sessionTimeout = 5000ms
        ZooKeeper zk = new ZooKeeper("127.0.0.1:2181", 5000, event -> {
            System.out.println("State: " + event.getState());
            System.out.println("Type: " + event.getType());
        });

        // 等待连接建立
        Thread.sleep(1000);

        long sessionId = zk.getSessionId();
        byte[] sessionPasswd = zk.getSessionPasswd();
        System.out.printf("SessionID: 0x%x, Timeout: %d%n",
                sessionId, zk.getSessionTimeout());

        // 创建临时节点
        zk.create("/session-ephemeral", "data".getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE,
                CreateMode.EPHEMERAL);

        System.out.println("Ephemeral node created");

        // 模拟断连
        Thread.sleep(20000);  // 超过 Session Timeout
        // 输出:State: Expired
        // 此时 Session 已失效

        zk.close();
    }
}

执行结果:

SessionID: 0x1000000001, Timeout: 5000
Ephemeral node created
State: Expired
Type: None

操作前后对比:

阶段Session 状态Ephemeral 节点Watcher
连接建立CONNECTED创建成功已注册
连接中CONNECTED存活等待触发
超时后EXPIRED被服务端删除被清除

示例三:Session 迁移与重连

场景说明:客户端从 Server A 断开,在 Session Timeout 内自动重连到 Server B,Session 不变。

ZooKeeper zk = new ZooKeeper(
    "192.168.1.10:2181,192.168.1.11:2181,192.168.1.12:2181",
    15000, watchedEvent -> {
        if (watchedEvent.getState() ==
                Watcher.Event.KeeperState.SyncConnected) {
            System.out.println("Reconnected: " +
                    watchedEvent.getPath());
        }
    }
);

// Session 属性保持不变
System.out.println("SessionId: " + zk.getSessionId());

操作前后对比:

维度操作前(Server A)操作后(Server B)
Session ID0x10000000010x1000000001(不变)
Ephemeral 节点存活存活(未被删除)
Watcher 注册有效自动重新注册

Session 迁移的关键前提:必须在 Session Timeout 时间内完成重连。一旦超时,Session 即过期且不可恢复。

易错场景与面试考点

易错场景

1. 将 Session Timeout 设得过小

ZooKeeper zk = new ZooKeeper("host:2181", 1000, watcher); // 1s

网络偶尔抖动就可能触发超时,频繁重连和 Expired 事件导致临时节点被反复删除重建。生产环境通常设置 10s ~ 30s。

2. Session Timeout 被服务端修改

客户端请求 timeout=50000ms,但服务端 maxSessionTimeout 默认 40000ms,最终实际 timeout 为 40000ms。配置服务端时需注意 maxSessionTimeout 参数。

3. Expired 后重用旧的 ZooKeeper 实例

Session 过期后旧的 ZooKeeper 实例已不可用,必须 close() 后重新 new ZooKeeper()。错误示范:

// 错误:Session 过期后仍使用旧实例
zk.create(...); // ConnectionLossException

面试高频题

Q:Session ID 是如何分配的?

A:Session ID 由 Leader 分配。客户端连接被路由到 Leader,Leader 生成全局唯一的 64 位 Session ID 并记录在内存和事务日志中。即使 Leader 变更,Session ID 也不会冲突。

Q:服务端如何检测 Session 过期?

A:服务端为每个 Session 维护一个过期计时器。每次收到该 Session 的任何请求(包括 ping),计时器重置为 timeout 值。如果计时器倒计时结束仍未收到请求,服务端将 Session 标记为 expired:

  1. 删除该 Session 的所有 Ephemeral 节点
  2. 清理所有关联的 Watcher
  3. 向其他 Server 广播 Session 失效信息

Q:Session Timeout 与 tickTime 的关系?

A:minSessionTimeout = 2 * tickTime,maxSessionTimeout = 20 * tickTime。客户端请求的 timeout 必须落在 [min, max] 范围内,否则被服务端调整。tickTime 是心跳间隔的基础单位。

小结

要点说明
Session ID全局唯一,Leader 分配
心跳客户端任何请求都视为心跳
状态机CONNECTING → CONNECTED → EXPIRED/CLOSED
Session 迁移超时前重连到新 Server,Session 保持不变
Local Session3.5+ 本地会话,无需 Quorum 确认,不可创建 Ephemeral
Timeout 协商服务端约束在 [min, max] 范围内
Ephemeral 绑定Session 过期时全部删除

Session 是 ZooKeeper 的生命线。下一节深入 Watcher 机制,理解基于 Session 的事件通知如何驱动分布式协调。

下一页
Watcher 机制