Skip to content

ZooKeeper 专栏

ZooKeeper 是分布式协调组件。它不是数据库,也不是缓存,更不是业务请求网关。它擅长解决分布式系统里的“协调问题”:服务注册发现、配置通知、分布式锁、选主、集群成员管理、状态变更监听等。

很多人只知道 Dubbo 可以用 ZooKeeper 做注册中心,但不理解为什么 ZooKeeper 能做注册中心、为什么能做分布式锁、为什么强调顺序一致性、临时节点和 Watcher。这个专栏要把这些原理讲清楚。

学习目标

能力具体要求
会用能启动 ZK,使用 Curator 创建节点、监听节点、实现锁和选主
懂模型理解 znode、临时节点、顺序节点、Watcher、Session
懂一致性理解 ZAB、Leader、Follower、过半写入、顺序一致性
会选型知道 ZK、Redis、etcd、Nacos、数据库锁各适合什么
会排查能排查连接抖动、Session 过期、锁不释放、脑裂误解、节点过多
会面试能讲清 ZK 为什么适合协调,不适合高频业务读写

本专栏学习路径

阶段文档学习重点
入门ZooKeeper 总览明确 ZK 解决什么问题
模型znode、Stat、版本CAS、ACL与multi节点类型、三类version、顺序号边界、ACL、容量与结果未知
一致性ZAB选主、广播与恢复全过程Proposal/ACK/Commit、epoch、zxid、Quorum、DIFF/TRUNC/SNAP与读一致性
通知Watcher与Session全过程连接状态、重连过期、一次性/持久Watch、GC Pause和安全恢复
场景分布式锁、选主与Fencing前驱Watch、Session失效、Fencing Token、Leader任务幂等
运维部署、日志、Snapshot、监控与故障恢复Quorum拓扑、磁盘、容量、安全、滚动升级和生产Runbook
面试ZooKeeper 面试题标准回答、追问点和原理跳转

ZooKeeper 解决什么问题

分布式系统里多个进程要协作,就会出现这些问题:

问题举例ZK 能力
谁是主节点多个调度器只能一个执行主任务选主
服务地址在哪里Consumer 要发现 Provider注册发现
配置变了谁通知应用动态开关、路由规则Watcher
多实例抢同一资源只有一个实例能重建缓存分布式锁
集群成员变化节点上线下线要感知临时节点和 Watcher

一句话:

ZooKeeper 适合做低频、关键、强协调的元数据管理,不适合做高频业务数据读写。

ZooKeeper 不是什么

误解正确认知
ZK 是数据库ZK 存少量协调元数据,不存大量业务数据
ZK 是缓存ZK 不是为高吞吐缓存设计的
ZK 是消息队列Watcher 是通知机制,不是可靠消息队列
ZK 会转发 Dubbo 请求ZK 只保存服务地址,不转发业务流量
ZK 锁一定比 Redis 锁好一致性更强但吞吐更低,适合低频关键协调

核心模型图

mermaid
flowchart TD
    A["ZooKeeper 集群"] --> B["Leader"]
    A --> C["Follower"]
    A --> D["Observer"]
    B --> E["处理写请求"]
    C --> F["参与投票和读请求"]
    D --> G["只服务读请求不投票"]
    E --> H["znode 节点树"]
    F --> H
    G --> H

ZooKeeper 对外看起来像一棵文件系统树,但它的节点叫 znode。每个 znode 可以保存少量数据,也可以有子节点。

text
/services
  /stock-service
    /providers
      /provider-0000000001
      /provider-0000000002
/locks
  /rebuild-cache
    /lock-0000000001
    /lock-0000000002

ZooKeeper 为什么适合注册中心

注册中心需要这些能力:

需求ZK 对应能力
Provider 上线写地址创建节点
Provider 异常宕机自动下线临时节点随 Session 过期删除
Consumer 感知地址变化Watcher 通知
多 Provider 地址有顺序顺序节点或节点列表
注册数据一致ZAB 保证写入顺序和多数派一致

流程:

mermaid
flowchart TD
    A["Provider 启动"] --> B["创建临时节点"]
    B --> C["Consumer 监听 providers 目录"]
    C --> D["Provider 宕机"]
    D --> E["Session 过期"]
    E --> F["临时节点删除"]
    F --> G["Consumer 收到变更通知"]

ZooKeeper 为什么能做分布式锁

ZK 常用“临时顺序节点”实现锁:

mermaid
flowchart TD
    A["多个客户端创建临时顺序节点"] --> B["获得节点序号"]
    B --> C{"自己是不是最小序号"}
    C -- "是" --> D["获得锁"]
    C -- "否" --> E["监听前一个节点"]
    E --> F["前一个节点删除"]
    F --> C

为什么监听前一个节点,而不是所有客户端都监听最小节点?

如果所有客户端都监听最小节点,锁释放时会唤醒所有等待者,造成羊群效应。监听前一个节点,只唤醒下一个候选者,效率更高。

最小 Demo:Curator 创建节点

Maven 依赖示例:

xml
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>5.6.0</version>
</dependency>

创建持久节点:

java
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;

import java.nio.charset.StandardCharsets;

public class ZookeeperCreateNodeDemo {

    public static void main(String[] args) throws Exception {
        CuratorFramework client = CuratorFrameworkFactory.newClient(
                "127.0.0.1:2181",
                new ExponentialBackoffRetry(1000, 3)
        );
        client.start();

        String path = "/demo/config";
        if (client.checkExists().forPath(path) == null) {
            client.create()
                    .creatingParentsIfNeeded()
                    .forPath(path, "enabled=true".getBytes(StandardCharsets.UTF_8));
        }

        byte[] data = client.getData().forPath(path);
        System.out.println(new String(data, StandardCharsets.UTF_8));

        client.close();
    }
}

商业常用场景

场景怎么用 ZK注意点
Dubbo 注册中心Provider 写临时节点,Consumer 监听目录不承载业务流量
分布式锁临时顺序节点适合低频关键锁,不适合高频热点锁
选主多实例竞争 LeaderLeader 挂了要能恢复状态
配置通知Watcher 监听配置节点配置量不能太大,通知后要重新读取
调度器主备一个 Leader 负责调度任务本身仍要幂等
集群成员管理节点以临时节点注册Session 抖动会引起成员变化

常见坑

后果正确做法
存大量业务数据ZK 内存和同步压力大只存少量元数据
高频写 ZKLeader 压力大,延迟升高高频数据放 Redis、DB、MQ
Watcher 当 MQ 用通知丢语义、只触发一次Watch 后重新注册并读取最新数据
Session 超时设置太短网络抖动导致临时节点误删根据网络和 GC 情况设置
锁内执行太久其他客户端长时间等待锁内只做短事务,业务要幂等
认为 ZK 避免所有脑裂客户端网络分区仍需业务兜底状态机、Fencing Token、幂等

与其他组件对比

组件更适合不适合
ZooKeeper选主、协调、注册、低频分布式锁高频业务读写、大对象存储
Redis高性能缓存、计数、热点锁强一致协调和选主
etcd云原生元数据、K8s 后端、强一致 KV传统 Java Dubbo 老项目兼容成本
NacosSpring Cloud Alibaba 注册配置通用分布式锁和选主不是主定位
MySQL业务数据和事务高频协调通知

面试标准回答

ZooKeeper 是分布式协调组件,提供类似文件树的 znode 数据模型,支持持久节点、临时节点、顺序节点、Watcher 通知和 Session 会话。它通过 ZAB 协议保证写请求的顺序一致性和多数派提交,因此适合做注册中心、配置通知、分布式锁、选主和集群成员管理。它不适合存大量业务数据,也不适合高频读写。

本章小结

ZooKeeper 的核心不是“存数据”,而是“协调”。临时节点解决进程存活感知,顺序节点解决排队,Watcher 解决变化通知,ZAB 解决多节点写入一致性。理解这四个点,才能真正理解 ZooKeeper 为什么能支撑注册中心、锁和选主。