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 为什么能支撑注册中心、锁和选主。