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

    • 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章 面试考点与设计思想

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

本章定位:ZNode 是 ZooKeeper 数据模型的基本单元。理解 ZNode 的类型、属性和操作语义,是使用 ZooKeeper 的起点。

定义与作用

ZooKeeper 的数据模型类似一个分布式文件系统,采用树形层次命名空间。树中的每个节点称为 ZNode。与文件系统的关键区别在于:ZNode 既可以像目录一样拥有子节点,又可以像文件一样存储数据。

ZNode 解决的核心痛点:

痛点ZNode 解决方案
配置数据分散统一存储在命名空间的路径上,所有客户端看到一致视图
临时节点管理Ephemeral 节点随会话自动删除,天然表达"存活"语义
全局唯一 IDSequence 节点自动追加单调递增编号
数据版本控制Stat 中的 version 字段实现乐观锁

核心原理

树形命名空间

图中 /app/config 存储持久配置数据,/app/services/ 下的子节点为 Ephemeral 类型(服务实例存活标识),/app/locks/ 下为带序号的临时节点。

ZNode 的核心属性

每个 ZNode 维护一个 Stat 结构,包含以下字段:

字段含义场景
czxid创建该节点的事务 ID追踪创建时序
mzxid最后一次修改该节点数据的事务 ID判断数据是否有更新
ctime创建时间(毫秒级时间戳)生命周期追踪
mtime最后修改时间数据新鲜度判断
version数据版本号(每次 setData +1)乐观锁 CAS 校验
cversion子节点列表版本号(子节点增删 +1)监听子节点变化
aversionACL 版本号ACL 变更追踪
ephemeralOwner临时节点的持有者 Session ID0 表示持久节点
dataLength数据长度(字节)数据大小限制校验
numChildren直接子节点数量目录类节点容量

完整示例

示例一:基本 CRUD 操作

场景说明:模拟配置中心场景,创建、读取、更新和删除配置节点。

操作前状态:空 ZooKeeper 树。

zkCli.sh -server 127.0.0.1:2181

创建节点:

[zkshell: 0] create /app "application-root"
Created /app

[zkshell: 1] create /app/config "port=8080,debug=false"
Created /app/config

读取数据:

[zkshell: 2] get /app/config
port=8080,debug=false
cZxid = 0x2
ctime = Sat Jun 13 10:00:00 CST 2026
mZxid = 0x2
mtime = Sat Jun 13 10:00:00 CST 2026
pZxid = 0x2
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 24
numChildren = 0

更新数据:

[zkshell: 3] set /app/config "port=9090,debug=true"
cZxid = 0x2
...
mZxid = 0x3          # 事务 ID 递增
dataVersion = 1      # 版本号从 0 → 1

[zkshell: 4] get /app/config
port=9090,debug=true

操作后状态:

ZNodedataVersion数据
/app0application-root
/app/config1port=9090,debug=true

版本号乐观锁演示:

# 使用旧版本号更新——失败
[zkshell: 5] set -v 0 /app/config "should fail"
version No is not valid : /app/config
# KeeperErrorCode = BadVersion

版本号机制保证了并发安全:客户端读到的 version=1,如果在此期间其他客户端已更新为 version=2,则使用 version=1 的 set 操作会失败。

示例二:ZNode 的 Stat 追踪

场景说明:通过 Java API 观察 ZNode 创建、修改全过程的版本变化。

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

public class ZNodeStatDemo {
    public static void main(String[] args) throws Exception {
        ZooKeeper zk = new ZooKeeper("127.0.0.1:2181", 3000, event -> {});

        // 1. 创建节点
        String path = zk.create("/stat-demo", "v1".getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        System.out.println("Created: " + path);

        // 2. 获取 Stat
        Stat stat = new Stat();
        byte[] data = zk.getData("/stat-demo", false, stat);
        System.out.printf("version=%d, data=%s%n",
                stat.getVersion(), new String(data));

        // 3. 更新数据
        stat = zk.setData("/stat-demo", "v2".getBytes(), stat.getVersion());
        System.out.printf("After setData: version=%d%n", stat.getVersion());

        // 4. 创建子节点
        zk.create("/stat-demo/child", "child-data".getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

        // 5. 再次获取 Stat
        stat = zk.exists("/stat-demo", false);
        System.out.printf("cversion=%d, numChildren=%d%n",
                stat.getCversion(), stat.getNumChildren());

        zk.close();
    }
}

执行结果:

Created: /stat-demo
version=0, data=v1
After setData: version=1
cversion=1, numChildren=1

操作前后对比:

时间点versioncversion说明
create 后00首次创建
setData 后10只修改了数据
创建子节点后11只修改了子节点列表

示例三:数据大小限制

场景说明:验证 ZNode 数据量上限(默认 1MB)。

# 尝试写入超过 1MB 的数据
[zkshell: 0] create /large_node "(此处为超过 1MB 的字符串)"
# KeeperErrorCode = MarshallingError

操作前状态:未超出限制的节点正常创建。

操作结果:超出 1MB 限制时,服务端直接拒绝,抛出 MarshallingError。

ZooKeeper 不是通用数据库,ZNode 设计目标存储的是协调元数据(配置、状态等),通常在 KB 级别。大数据应存储在 HDFS 等系统,ZooKeeper 中只存储指针。

易错场景与面试考点

易错场景

1. 空节点不等于不存在的节点

create /empty ""
# 创建成功,dataLength=0

get /empty
# 返回空字符串,但 Stat 有效

stat /not-exist
# KeeperErrorCode = NoNode

dataLength=0 和 NoNode 是两种完全不同的状态。前者是存在的空数据节点,后者是不存在的路径。

2. version 不是全局自增 ID

容易将 version 误解为"第几次修改"。实际上 version 表示该节点自身被修改的次数,不同节点的 version 值互相独立。

3. ZNode 路径约束

以下字符不可用于路径:

  • \u0000(空字符)
  • 控制字符 \u0001 ~ \u001F、\u007F ~ \u009F
  • Unicode 代理区 \ud800 ~ \uF8FF、\uFFF0 ~ \uFFFF
  • . 和 .. 不能作为独立路径段
  • zookeeper 是保留关键字

面试高频题

Q:ZooKeeper 的数据模型与文件系统有何异同?

A:

  • 相同点:树形结构、层次命名空间、路径访问(/a/b/c)
  • 不同点:ZNode 可同时拥有数据和子节点(文件系统只能二选一);ZNode 支持 Ephemeral/Sequential 等特殊类型;数据大小限制在 1MB 以内;不支持相对路径。

Q:version 字段有什么用?

A:version 是实现乐观锁的核心。每次 setData 前传入期望的 version,服务端校验一致才写入。这保证了在分布式环境下无需额外加锁即可实现原子 CAS 操作。

Q:ephemeralOwner 什么时候为 0?

A:持久节点(Persistent)的 ephemeralOwner 始终为 0。只有临时节点(Ephemeral)的 ephemeralOwner 才是创建它的 Session ID。

小结

要点说明
ZNode 是树形结构的节点兼具数据存储与目录组织能力
Stat 结构版本号、时间戳、事务 ID、子节点数的完整元数据
version 乐观锁通过 CAS 保证并发安全更新
数据上限 1MB适合协调元数据,不适合大对象存储
路径约束禁止特定 Unicode 字符,不支持相对路径

ZNode 是后续所有机制的基础。下一节将深入不同类型的 ZNode(持久/临时/顺序)及其适用场景。

下一页
节点类型对比