1. ZooKeeper 核心概念
1.1 数据模型:ZNode
ZooKeeper 的数据存储采用类似文件系统的树形结构(层次命名空间 ),每个节点称为 ZNode,特点如下:
- 持久节点(Persistent):创建后即使客户端断开连接也不会删除(除非手动删除)。
- 临时节点(Ephemeral):客户端会话结束后自动删除(适用于服务注册与发现)。
- 顺序节点(Sequential) :节点名自动追加单调递增序号(如
/lock-0000000001
),适用于分布式锁。 - 节点数据(Data):每个 ZNode 可存储少量数据(默认 ≤1MB),通常用于存储配置或状态信息。
1.2 集群角色
- Leader :
- 负责处理所有写请求(如创建/删除 ZNode)。
- 通过 ZAB 协议保证写操作的全局顺序性。
- Follower :
- 处理读请求,并参与 Leader 选举。
- 同步 Leader 的数据变更。
- Observer :
- 仅处理读请求,不参与选举(提高读扩展性)。
1.3 Watcher 机制
客户端可对 ZNode 设置 Watcher 监听其变化(如节点创建、删除、数据更新),触发后 ZooKeeper 会向客户端发送事件通知(一次性触发,需重新注册)。
2. ZooKeeper 核心原理
2.1 ZAB 协议(ZooKeeper Atomic Broadcast)
ZAB 协议是 ZooKeeper 实现一致性的核心,分为两个阶段:
- 崩溃恢复(Leader Election) :
- 当 Leader 宕机时,集群进入恢复模式,通过 Fast Leader Election 快速选举新 Leader。
- 新 Leader 会同步所有 Follower 的数据,确保状态一致。
- 消息广播(Atomic Broadcast) :
- Leader 接收写请求后,生成 Proposal 广播给所有 Follower。
- 收到半数以上 ACK 后,Leader 提交事务并通知 Follower 写入数据。
特点:
- 强一致性:所有写操作按全局顺序执行。
- 高可用:只要半数以上节点存活,集群仍可用(如 3 节点集群允许 1 节点故障)。
2.2 会话(Session)
- 客户端与 ZooKeeper 服务器建立 TCP 长连接,会话期间保持心跳。
- Session Timeout:若超时未收到心跳,服务端认为客户端失效,删除其临时节点。
3. ZooKeeper 典型应用场景
3.1 分布式锁
java
// 加锁(创建临时顺序节点)
String lockPath = zk.create("/lock/seq-", EPHEMERAL_SEQUENTIAL);
// 检查是否是最小序号节点(获取锁)
List<String> children = zk.getChildren("/lock", false);
if (Collections.min(children).equals(lockPath)) {
// 获取锁成功
} else {
// 监听前一个节点,等待锁释放
}
优点:避免单点故障,支持可重入锁、公平锁。
3.2 服务注册与发现
- 服务注册 :服务启动时创建临时节点(如
/services/serviceA/192.168.1.1:8080
)。 - 服务发现 :客户端监听
/services/serviceA
的子节点变化,获取可用服务列表。
3.3 配置管理
- 将全局配置(如数据库连接串)存储在持久节点
/config/db_url
。 - 客户端监听该节点,配置变更时实时更新。
3.4 选主(Leader Election)
- 多个候选节点创建临时顺序节点,序号最小者成为 Leader。
- 其他节点监听 Leader 节点,若 Leader 失效则重新选举。
4. ZooKeeper 性能优化
4.1 读写分离
- 读请求直接由 Follower/Observer 处理,降低 Leader 负载。
- 写请求仍需通过 Leader 保证一致性。
4.2 避免 Watcher 风暴
- Watcher 是一次性 的,需谨慎注册(如使用
Curator
框架的TreeCache
自动递归监听)。
4.3 合理设置 ZNode 数据大小
- 单个 ZNode 数据建议 ≤1KB,避免序列化/反序列化开销。
4.4 集群部署优化
- 节点数建议为奇数(如 3、5),确保选举能达成多数派。
- 物理隔离:将 Follower 分散在不同机架,提高容灾能力。
5. ZooKeeper 局限性
问题 | 原因/影响 | 解决方案 |
---|---|---|
写性能瓶颈 | 所有写请求由 Leader 处理 | 分片(如 Kafka 用多 Partition) |
非强一致性读 | Follower 可能读到旧数据 | 使用 sync() 方法强制同步 |
Watcher 丢失 | 一次性触发,易遗漏事件 | 配合日志 + 定时全量拉取 |
脑裂问题 | 网络分区导致多 Leader | 依赖 ZAB 协议自动恢复 |
6. ZooKeeper vs. 其他协调服务
特性 | ZooKeeper | etcd | Consul |
---|---|---|---|
一致性协议 | ZAB | Raft | Raft |
数据模型 | 树形 ZNode | 键值对 | 键值对 + 服务发现 |
读写性能 | 写性能较低(依赖 Leader) | 读写均衡 | 读写均衡 |
适用场景 | 强一致性场景(如锁、选主) | Kubernetes 配置管理 | 服务网格(如 Istio) |
7. 实践建议
- 使用高级客户端 :
- 推荐 Apache Curator,封装了重试机制、分布式锁等常用模式。
- 监控关键指标 :
znode_count
、watch_count
、latency
(通过zkServer.sh status
或 Prometheus)。
- 避免滥用 :
- 不适合存储大规模数据(如文件),仅用于协调元数据。
8. 总结
- ZooKeeper 核心价值 :提供分布式系统中的强一致性协调服务,基于 ZAB 协议实现高可用。
- 最佳实践:用于分布式锁、服务发现、配置管理等场景,需合理设计 ZNode 结构和 Watcher。
- 局限性:写性能有限,大规模数据存储需选择其他方案(如 Redis 或分布式数据库)。