ZooKeeper 入门教程
2025/8/15大约 4 分钟
ZooKeeper 入门教程
前置知识
在开始本教程之前,建议您具备以下基础知识:
- Java 基础语法
- 分布式系统基础概念
- Linux 基本操作
什么是 ZooKeeper?
ZooKeeper 是一个开源的分布式协调服务,由 Apache 软件基金会开发和维护。它主要用于:
- 配置管理:集中管理分布式系统的配置信息
- 命名服务:为分布式系统中的资源提供统一的命名
- 分布式锁:实现分布式系统中的互斥和同步
- 集群管理:监控集群中机器的上下线状态
ZooKeeper 特性
- 顺序一致性:客户端的更新请求按发送顺序执行
- 原子性:更新要么成功要么失败,没有中间状态
- 单一视图:无论连接到哪个服务器,客户端看到的数据都是一致的
- 可靠性:一旦更新成功,数据将持久保存
- 实时性:在一定时间范围内,客户端能读到最新数据
核心概念
数据模型
ZooKeeper 的数据模型类似于文件系统的树形结构:
/
├── app1
│ ├── config
│ └── status
└── app2
├── config
└── status
每个节点称为 ZNode,可以存储数据并挂载子节点。
节点类型
- 持久节点:一旦创建,除非主动删除,否则一直存在
- 临时节点:与客户端会话绑定,会话结束自动删除
- 顺序节点:节点名自动追加递增序号
- 临时顺序节点:结合临时节点和顺序节点的特性
环境准备
1. 下载安装
访问 Apache ZooKeeper 官网 下载最新稳定版:
# 下载并解压
wget https://downloads.apache.org/zookeeper/stable/apache-zookeeper-3.7.1-bin.tar.gz
tar -zxf apache-zookeeper-3.7.1-bin.tar.gz
# 创建数据目录
mkdir /data/zookeeper
2. 基础配置
创建配置文件 conf/zoo.cfg
:
# 基本配置
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper
clientPort=2181
# 集群配置(单机模式可省略)
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888
3. 添加依赖
在您的 pom.xml
中添加 ZooKeeper 依赖:
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.7.1</version>
</dependency>
<!-- Curator 框架(推荐使用)-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.3.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.3.0</version>
</dependency>
快速入门
1. 创建连接
使用 Curator 框架连接 ZooKeeper:
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ZkClient {
private final CuratorFramework client;
public ZkClient(String connectString) {
// 创建客户端
client = CuratorFrameworkFactory.builder()
.connectString(connectString)
.sessionTimeoutMs(5000)
.connectionTimeoutMs(3000)
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
.build();
// 启动客户端
client.start();
log.info("ZooKeeper 客户端已启动");
}
public CuratorFramework getClient() {
return client;
}
}
2. 基本操作
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
public class ZkDemo {
private final CuratorFramework client;
public ZkDemo(CuratorFramework client) {
this.client = client;
}
// 创建节点
public void createNode(String path, String data) throws Exception {
client.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.PERSISTENT)
.forPath(path, data.getBytes());
}
// 获取节点数据
public String getData(String path) throws Exception {
byte[] bytes = client.getData().forPath(path);
return new String(bytes);
}
// 更新节点数据
public void updateData(String path, String data) throws Exception {
client.setData().forPath(path, data.getBytes());
}
// 删除节点
public void deleteNode(String path) throws Exception {
client.delete()
.guaranteed()
.deletingChildrenIfNeeded()
.forPath(path);
}
}
3. 监听示例
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
public class ZkWatcherDemo {
private final CuratorFramework client;
public ZkWatcherDemo(CuratorFramework client) {
this.client = client;
}
// 监听子节点变化
public void watchChildren(String path) throws Exception {
PathChildrenCache cache = new PathChildrenCache(client, path, true);
cache.start();
cache.getListenable().addListener((client, event) -> {
switch (event.getType()) {
case CHILD_ADDED:
log.info("子节点已添加:{},数据:{}",
event.getData().getPath(),
new String(event.getData().getData()));
break;
case CHILD_UPDATED:
log.info("子节点已更新:{},新数据:{}",
event.getData().getPath(),
new String(event.getData().getData()));
break;
case CHILD_REMOVED:
log.info("子节点已删除:{}", event.getData().getPath());
break;
default:
break;
}
});
}
}
最佳实践
注意事项
- 会话管理:及时关闭不再使用的会话
- 异常处理:正确处理连接断开、会话过期等异常
- 节点设计:合理规划节点结构,避免过深的层级
- 数据大小:节点数据应保持精简,建议小于1MB
性能优化
- 连接池:在高并发场景使用连接池
- 监听器:避免注册过多的监听器
- 批量操作:使用事务机制批量处理操作
常见问题
1. 如何处理连接断开?
使用 Curator 的重试机制和连接状态监听:
// 监听连接状态
client.getConnectionStateListenable().addListener((client, state) -> {
if (state == ConnectionState.LOST) {
log.warn("连接丢失");
} else if (state == ConnectionState.RECONNECTED) {
log.info("重新连接成功");
}
});
2. 如何实现分布式锁?
使用 Curator 提供的分布式锁实现:
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
// 创建分布式锁
InterProcessMutex lock = new InterProcessMutex(client, "/locks/mylock");
try {
// 获取锁
lock.acquire();
// 执行业务逻辑
doSomething();
} finally {
// 释放锁
lock.release();
}
总结
本教程介绍了 ZooKeeper 的基础知识,包括:
- ✅ 核心概念:数据模型和节点类型
- ✅ 环境搭建:安装配置和依赖管理
- ✅ 基本操作:节点的增删改查
- ✅ 监听机制:事件监听示例
- ✅ 最佳实践:注意事项和优化建议
下一步学习
- 深入了解 ZooKeeper 的分布式锁实现
- 学习 ZooKeeper 的集群部署
- 探索 ZooKeeper 在微服务中的应用