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

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

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

本章定位:顺序节点是 ZooKeeper 实现分布式锁、队列和全局唯一 ID 生成的核心机制。理解其编号原理和使用方式是构建分布式协调应用的关键。

定义与作用

顺序节点(Sequential ZNode) 是在创建时由 ZooKeeper 自动在路径末尾追加 10 位单调递增数字的 ZNode。格式为 path前缀 + 0000000001。

create -s /tasks/task- ""
# 实际创建: /tasks/task-0000000001

核心特征:

  • 计数器由父节点维护,每个父节点独立计数
  • 严格单调递增,不重号(单个父节点范围内)
  • 10 位数字零填充,支持字典序排序
  • 可与 Persistent 或 Ephemeral 组合

核心原理

序号生成机制

序号由 Leader 原子分配,保证全局唯一和严格递增。即使多个客户端同时创建,也能得到不重复的序号。

计数器特性

属性说明
存储位置父节点的 Stat 中,由 cversion 字段关联
数值范围32 位有符号整数(-2147483648 ~ 2147483647)
溢出行为达到最大值后翻转为负数
格式%010d(10 位零填充)
起始值从 0 开始,即 0000000000

完整示例

示例一:分布式任务队列

场景说明:多个 Worker 从任务队列中按顺序取任务执行。

创建任务(Producer):

zkCli.sh -server 127.0.0.1:2181

[zkshell: 0] create /tasks "Task Queue Root"
Created /tasks

[zkshell: 1] create -s /tasks/job- "process_order_001"
Created /tasks/job-0000000000

[zkshell: 2] create -s /tasks/job- "process_order_002"
Created /tasks/job-0000000001

[zkshell: 3] create -s /tasks/job- "process_order_003"
Created /tasks/job-0000000002

[zkshell: 4] ls /tasks
[job-0000000000, job-0000000001, job-0000000002, zookeeper]

消费任务(Worker):

// Worker 获取序号最小的任务
List<String> tasks = zk.getChildren("/tasks", false);
Collections.sort(tasks);
String firstTask = tasks.get(0);
byte[] data = zk.getData("/tasks/" + firstTask, false, null);
System.out.println("Processing: " + new String(data));

// 处理完成后删除
zk.delete("/tasks/" + firstTask, -1);

操作前后对比:

阶段/tasks 子节点(按序排列)说明
生产阶段job-0000000000 ~ job-00000000023 个待处理任务
Worker 1 取走 job-0job-0000000001, job-0000000002按序消费
Worker 2 取走 job-1job-0000000002继续按序消费

示例二:全局唯一 ID 生成器

场景说明:分布式系统中不同服务实例生成不重复的订单 ID。

# 创建 ID 根节点
create /order-ids "Order ID Root"

# 各服务实例生成 ID
# Service A
create -s /order-ids/ORD- ""
# → /order-ids/ORD-0000000000

# Service B
create -s /order-ids/ORD- ""
# → /order-ids/ORD-0000000001

# Service A 再次生成
create -s /order-ids/ORD- ""
# → /order-ids/ORD-0000000002

Java 实现:

public String generateOrderId() {
    String path = zk.create("/order-ids/ORD-",
            null,
            ZooDefs.Ids.OPEN_ACL_UNSAFE,
            CreateMode.PERSISTENT_SEQUENTIAL);
    // path 为 "/order-ids/ORD-0000000000"
    return path.substring("/order-ids/".length());
}

操作前后对比:

服务实例生成的 ID是否会重复
Service A 第 1 次ORD-0000000000否
Service B 第 1 次ORD-0000000001否
Service A 第 2 次ORD-0000000002否

示例三:公平分布式锁队列

场景说明:通过 Ephemeral Sequential 实现排队,序号最小的获取锁。

public class FairLock {
    private ZooKeeper zk;
    private String lockPath = "/fair-lock";
    private String myNode;

    public void acquire() throws Exception {
        // 创建临时顺序节点
        myNode = zk.create(lockPath + "/req-", null,
                ZooDefs.Ids.OPEN_ACL_UNSAFE,
                CreateMode.EPHEMERAL_SEQUENTIAL);

        List<String> children = zk.getChildren(lockPath, false);
        Collections.sort(children);

        String nodeName = myNode.substring(lockPath.length() + 1);
        if (children.get(0).equals(nodeName)) {
            // 序号最小,获取锁
            return;
        }

        // 否则等待前一个节点释放
        int idx = children.indexOf(nodeName);
        String prevNode = lockPath + "/" + children.get(idx - 1);

        CountDownLatch latch = new CountDownLatch(1);
        zk.exists(prevNode, event -> latch.countDown());
        latch.await();
    }
}

执行时序:

时刻Client AClient BClient C锁持有者
T1req-0001req-0002req-0003A
T2释放——B(Watch A 获通知)
T3—释放—C(Watch B 获通知)

易错场景与面试考点

易错场景

1. 将序号误解为全局计数器

顺序节点的序号是按父节点递增的,不同父节点的计数器独立:

create -s /tasks/t- ""    # /tasks/t-0000000000
create -s /jobs/j- ""     # /jobs/j-0000000000 —— 从 0 开始

两个父节点下的序号各自独立,没有全局统一计数器。

2. 字典序排序陷阱

10 位数字排序天然正确(因为是零填充),但非零填充的序号会有问题:

# 错误:非零填充
task-1, task-10, task-2  → 字典序 = [task-1, task-10, task-2]

# 正确:零填充
task-0000000001, task-0000000002, task-0000000010
→ 字典序 = [task-0000000001, task-0000000002, task-0000000010]

ZooKeeper 默认的零填充格式保证了字典序与数值序一致。

3. 大量顺序节点未及时清理

每个创建顺序节点的请求都需要 Leader 处理。如果只创建不删除,节点数量无限膨胀会导致:

  • 获取子节点列表的时间增长
  • 内存占用增加
  • 计数器溢出风险

应在任务完成后及时删除已处理的顺序节点。

面试高频题

Q:ZooKeeper 的顺序节点如何保证在分布式环境下的唯一性?

A:所有创建操作都必须经过 Leader。Leader 作为单点串行化所有写请求,原子地分配序号并写入事务日志。即使多个 Follower 收到客户端请求,也会转发给 Leader 处理,因此序号不会重复。

Q:ephemeral_sequential 和 persistent_sequential 的使用场景有什么区别?

A:

  • Ephemeral Sequential:适合临时性竞争场景(分布式锁),客户端断开后自动释放
  • Persistent Sequential:适合持久性场景(全局 ID 生成器、任务队列),需要保留历史记录

Q:计数器溢出会怎样?

A:计数器是 32 位有符号 int,溢出后变为负数,节点名会变成 prefix--2147483648。由于 ZooKeeper 的使用场景极难达到 20 亿次创建(即使是高频场景也需要持续运行数十年),实际发生概率极低。

小结

要点说明
序号格式10 位零填充(%010d)
计数器范围父节点独立维护,32 位有符号 int
原子性保证Leader 串行化创建请求
组合使用与 Ephemeral 组合实现公平分布式锁
字典序友好零填充保证字符串排序 = 数值排序

顺序节点是分布式锁的基石。下一节将全面对比四种节点类型及其最佳实践。

上一页
节点类型对比
下一页
ACL 权限控制