ZooKeeper 教程
ZooKeeper 是什么、核心概念(znode / session / watcher )、单机安装、zkCli 命令、典型应用场景与集群选举概览。
ZooKeeper 是什么
ZooKeeper is an Apache distributed coordination service, originally built by Yahoo for Hadoop. It tackles the hardest, most error-prone problems in distributed systems: centralised config, service discovery, leader election, and cross-process locks.
It does not store business data; instead it holds an in-memory tree of nodes (znode tree) where coordination state lives. Clients read, write and watch this tree with simple primitives, then build config centres, registries and locks on top.
应用 A ─┐ ┌─ 配置中心
应用 B ─┼──▶ ZooKeeper ◀──watch──┤
应用 C ─┘ (znode 树 + Watcher) └─ 选主 / 分布式锁核心概念
znode 数据模型
Data is organised like a file system: hierarchical paths (e.g. /app/conf), where each path element is a znode. Unlike a file system, each znode can both hold children and store a small payload (default limit 1 MB; keep only coordination data, never bulk objects).
节点类型
| 类型 | 特点 | 典型用途 |
|---|---|---|
| 持久节点 PERSISTENT | 客户端断开后依然存在 | 配置、元数据 |
| 临时节点 EPHEMERAL | 会话结束即删除,不能挂子节点 | 选主、存活探测 |
| 顺序节点 SEQUENTIAL | 创建时追加单调递增序号 | 分布式锁、公平队列 |
| 持久顺序 / 临时顺序 | 上面两类与顺序标志组合 | 锁、队列 |
Session 会话
A connection opens a session with a server-side timeout (e.g. 30s). As long as the client heartbeats within the timeout the session stays alive; on timeout, all its ephemeral nodes are deleted automatically — the basis for using ephemerals as liveness markers.
Watcher 监视器
A Watcher is how ZooKeeper delivers notifications. When calling exists / getData / getChildren a client can register a one-shot Watcher: when that node is created, deleted or its data changes, the server pushes an event. Watchers are one-shot — re-register after each trigger to keep watching.
版本与 ACL
Each znode keeps three versions: dataVersion, cversion, aversion. Writes can carry a version for optimistic locking (rejected on mismatch, preventing concurrent overwrite). ACLs control access via schemes like world, auth, digest and ip.
单机安装与启动
After extracting the download, the key file is conf/zoo.cfg. A minimal working config only needs a data directory and a port:
# conf/zoo.cfg
tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181
initLimit=5
syncLimit=2Start the server (bin/zkServer.sh on Linux/macOS, bin/zkServer.cmd on Windows):
# 启动
bin/zkServer.sh start
# 查看状态
bin/zkServer.sh statusZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
Mode: standalone命令行客户端 zkCli
zkCli.sh is the most direct tool. This connects to localhost:2181 and drops into an interactive prompt:
bin/zkCli.sh -server 127.0.0.1:2181Connecting to 127.0.0.1:2181
Welcome to ZooKeeper!
JLine support is enabled
[zk: 127.0.0.1:2181(CONNECTED) 0]Common commands:
ls / # 列出根下的子节点
create /app "hello" # 创建持久节点并写入数据
create -e /app/leader "" # 创建临时节点(会话结束消失)
create -s /queue/task- "" # 创建顺序节点,自动追加序号
get /app # 读取数据与 stat 信息
set /app "world" # 更新数据(dataVersion+1)
delete /app # 删除节点(有子节点时删不掉)(zk: 127.0.0.1:2181(CONNECTED) 0) ls /
[zookeeper]
(zk: 127.0.0.1:2181(CONNECTED) 1) create /app "hello"
Created /app
(zk: 127.0.0.1:2181(CONNECTED) 2) get /app
hello
cZxid = 0x2 ...
dataVersion = 0
dataLength = 5
numChildren = 0Watcher 实战:监听配置变化
Register a getData Watcher on /app, then change the data and the event fires — this is exactly how a config centre works:
get -w /app # -w 注册一次性 Watcher
set /app "new-config" # 另一个会话改数据(zk: ... CONNECTED 1) get -w /app
hello
WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/app
(zk: ... CONNECTED 2) set /app "new-config"
... NodeDataChanged 已触发,下次需重新 get -w典型应用场景
配置中心
Write config into a znode (e.g. /app/conf); apps getData on boot and register a Watcher. Changing config is a single set; every watching app gets the update within seconds and hot-reloads, no restart.
命名服务 / 注册中心
On startup a service creates an ephemeral sequential node under /services/order (e.g. order-0000000001); it vanishes when the session ends. Callers ls /services/order to get the live instance list — service registration and discovery for free.
分布式锁
To lock: create an ephemeral sequential node under /lock. If yours has the smallest sequence you hold the lock; otherwise watch the previous node's deletion. When it's gone you wake and re-check. Ephemerals guarantee the lock releases if the holder crashes — no deadlock.
选主(Leader Election)
Same idea as the lock: processes create sequential ephemerals under /election; the smallest becomes Leader. When it dies the node disappears, others get the event, and the next-smallest takes over. This smallest-wins pattern powers leader election in HBase, Kafka and more.
集群与选举概览
In a cluster, nodes take three roles: Leader handles writes and broadcasts; Follower votes and serves reads; Observer replicates but does not vote, scaling reads without hurting write latency. The ZAB protocol keeps every node consistent.
A three-node cluster lists every member in zoo.cfg:
tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181
server.1=10.0.0.1:2888:3888
server.2=10.0.0.2:2888:3888
server.3=10.0.0.3:2888:3888Port 2888 is for peer-to-peer sync, 3888 is for leader election. Each machine writes its id (1 / 2 / 3) into dataDir/myid. Election needs a majority: the first node to win more than half the votes becomes Leader.
zoo.cfg; only myid differs. A mismatched or missing server.N is the most common reason a cluster never elects a leader.小结
- ZooKeeper = in-memory node tree + Watcher, purpose-built for coordination
- Persistent / ephemeral / sequential nodes; ephemerals underpin leader election and liveness
- Watchers fire once; re-register to keep watching; versions give optimistic locking
- Config centre, discovery, distributed lock and leader election are the four classic use cases
- Run an odd-sized cluster in production; ZAB + quorum election guarantee consistency and availability
ZooKeeper 是什么
ZooKeeper 是 Apache 的分布式协调服务,最早由 Yahoo 为 Hadoop 研发,用来解决分布式系统里那些「最麻烦、最容易写错」的共性问题:配置怎么集中管理、服务在哪里注册、谁来做主节点、一把锁怎么在多个进程间互斥。
它本身不存业务数据,而是一棵常驻内存的节点树(znode tree),所有协调信息都以节点形式挂在树上。客户端通过简单的原语读写这棵树,再挂上监听器,就能构建出配置中心、注册中心、分布式锁等上层能力。
应用 A ─┐ ┌─ 配置中心
应用 B ─┼──▶ ZooKeeper ◀──watch──┤
应用 C ─┘ (znode 树 + Watcher) └─ 选主 / 分布式锁核心概念
znode 数据模型
ZooKeeper 的数据组织得像文件系统:有层级路径(如 /app/conf),路径上的每个节点叫一个 znode。但与文件系统不同,每个 znode 既能挂子节点,又能自己存一小段数据(默认上限 1 MB,建议只放协调信息,不要塞大对象)。
节点类型
| 类型 | 特点 | 典型用途 |
|---|---|---|
| 持久节点 PERSISTENT | 客户端断开后依然存在 | 配置、元数据 |
| 临时节点 EPHEMERAL | 会话结束即删除,不能挂子节点 | 选主、存活探测 |
| 顺序节点 SEQUENTIAL | 创建时追加单调递增序号 | 分布式锁、公平队列 |
| 持久顺序 / 临时顺序 | 上面两类与顺序标志组合 | 锁、队列 |
Session 会话
客户端连上 ZooKeeper 就建立一个 session,服务端给一个会话超时时间(如 30s)。只要客户端在超时内发过心跳,会话就一直有效;一旦超时,它创建的所有临时节点会被自动删除——这正是「临时节点 = 在线标记」能成立的原因。
Watcher 监视器
Watcher 是 ZooKeeper 实现「事件通知」的关键。客户端对某个节点调用 exists / getData / getChildren 时可以注册一个一次性 Watcher:当该节点被创建、删除或数据变化时,服务端会推一个事件给客户端。注意 Watcher 是一次性的——触发后需要重新注册,才能继续监听下一次变化。
版本与 ACL
每个 znode 维护三种版本号:dataVersion(数据版本)、cversion(子节点版本)、aversion(ACL 版本)。写操作可带版本做乐观锁(版本不匹配则拒绝,避免并发覆盖)。ACL 则负责权限控制,支持 world、auth、digest、ip 等 Scheme。
单机安装与启动
下载解压后,核心是一个配置文件 conf/zoo.cfg。最小可用配置只需给出数据目录和端口:
# conf/zoo.cfg
tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181
initLimit=5
syncLimit=2启动服务端(Linux/macOS 用 bin/zkServer.sh,Windows 用 bin/zkServer.cmd):
# 启动
bin/zkServer.sh start
# 查看状态
bin/zkServer.sh statusZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
Mode: standalone命令行客户端 zkCli
zkCli.sh 是最直接的操作入口。下面这条连本机 2181,连上后会进入交互提示符:
bin/zkCli.sh -server 127.0.0.1:2181Connecting to 127.0.0.1:2181
Welcome to ZooKeeper!
JLine support is enabled
[zk: 127.0.0.1:2181(CONNECTED) 0]常用命令一览:
ls / # 列出根下的子节点
create /app "hello" # 创建持久节点并写入数据
create -e /app/leader "" # 创建临时节点(会话结束消失)
create -s /queue/task- "" # 创建顺序节点,自动追加序号
get /app # 读取数据与 stat 信息
set /app "world" # 更新数据(dataVersion+1)
delete /app # 删除节点(有子节点时删不掉)(zk: 127.0.0.1:2181(CONNECTED) 0) ls /
[zookeeper]
(zk: 127.0.0.1:2181(CONNECTED) 1) create /app "hello"
Created /app
(zk: 127.0.0.1:2181(CONNECTED) 2) get /app
hello
cZxid = 0x2 ...
dataVersion = 0
dataLength = 5
numChildren = 0Watcher 实战:监听配置变化
在 /app 上注册一个 getData 的 Watcher,然后改数据,就能收到事件推送——配置中心的原理就在这里:
get -w /app # -w 注册一次性 Watcher
set /app "new-config" # 另一个会话改数据(zk: ... CONNECTED 1) get -w /app
hello
WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/app
(zk: ... CONNECTED 2) set /app "new-config"
... NodeDataChanged 已触发,下次需重新 get -w典型应用场景
配置中心
把配置写成一个 znode(如 /app/conf),应用启动时 getData 读取,再注册 Watcher。运维改了配置只需 set 一下,所有监听的应用会秒级收到变化并热更新,不用重启。
命名服务 / 注册中心
服务实例上线时在 /services/order 下创建一个临时顺序节点(如 order-0000000001),下线会话断开节点自动消失。调用方 ls /services/order 就能拿到当前所有活着的实例列表,天然实现了服务注册与发现。
分布式锁
抢锁 = 在 /lock 下创建临时顺序节点。创建后看自己是不是序号最小的那个:是就拿锁;不是就监听前一个节点的删除事件。前一个释放(节点消失)时自己被唤醒再判断。用临时节点保证:持锁进程崩溃,锁会自动释放,不会死锁。
选主(Leader Election)
和分布式锁同理:多个进程抢着在 /election 下建顺序临时节点,序号最小的成为 Leader。Leader 宕机后节点消失,其余进程监听到事件,序号最小的自动接替成为新 Leader。这种「最小序号即主」的模式在 HBase、Kafka 等系统里被广泛使用。
集群与选举概览
ZooKeeper 集群里节点分三种角色:Leader 负责写请求和广播;Follower 参与投票、处理读;Observer 只同步数据、不投票,用来横向扩展读能力而不影响写性能。集群通过 ZAB 协议保证所有节点数据一致。
一个三节点集群的 zoo.cfg 需要列出所有成员:
tickTime=2000
dataDir=/var/lib/zookeeper
clientPort=2181
server.1=10.0.0.1:2888:3888
server.2=10.0.0.2:2888:3888
server.3=10.0.0.3:2888:3888其中 2888 是对内通信端口(Leader 与 Follower 同步数据),3888 是选举端口(选主时互投)。每台机器还要在 dataDir/myid 里写入自己的编号(1 / 2 / 3)。Leader 选举采用过半同意原则:谁拿到超过半数选票谁当主。
myid 不同。配错一处(比如某台少了 server.3)会导致集群永远选不出主、一直超时——这是新手最常见的踩坑点。小结
- ZooKeeper = 内存节点树 + 观察者(Watcher),专治分布式协调难题
- 节点有持久 / 临时 / 顺序三类,临时节点是选主与存活探测的基石
- Watcher 一次性触发,监听要循环注册;版本号提供乐观锁
- 配置中心、注册发现、分布式锁、选主是四大经典场景
- 生产用奇数节点集群,靠 ZAB + 过半选举保证一致与可用