简单介绍ZooKeeper

27 阅读4分钟

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 实现一致性的核心,分为两个阶段:

  1. 崩溃恢复(Leader Election)
    • 当 Leader 宕机时,集群进入恢复模式,通过 Fast Leader Election 快速选举新 Leader。
    • 新 Leader 会同步所有 Follower 的数据,确保状态一致。
  2. 消息广播(Atomic Broadcast)
    • Leader 接收写请求后,生成 Proposal 广播给所有 Follower。
    • 收到半数以上 ACK 后,Leader 提交事务并通知 Follower 写入数据。

特点

  • 强一致性:所有写操作按全局顺序执行。
  • 高可用:只要半数以上节点存活,集群仍可用(如 3 节点集群允许 1 节点故障)。

2.2 会话(Session)

  • 客户端与 ZooKeeper 服务器建立 TCP 长连接,会话期间保持心跳。
  • Session Timeout:若超时未收到心跳,服务端认为客户端失效,删除其临时节点。

3. ZooKeeper 典型应用场景

3.1 分布式锁

// 加锁(创建临时顺序节点)
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. 其他协调服务

特性ZooKeeperetcdConsul
一致性协议ZABRaftRaft
数据模型树形 ZNode键值对键值对 + 服务发现
读写性能写性能较低(依赖 Leader)读写均衡读写均衡
适用场景强一致性场景(如锁、选主)Kubernetes 配置管理服务网格(如 Istio)

7. 实践建议

  1. 使用高级客户端
    • 推荐 Apache Curator,封装了重试机制、分布式锁等常用模式。
  2. 监控关键指标
    • znode_countwatch_countlatency(通过 zkServer.sh status 或 Prometheus)。
  3. 避免滥用
    • 不适合存储大规模数据(如文件),仅用于协调元数据。

8. 总结

  • ZooKeeper 核心价值:提供分布式系统中的强一致性协调服务,基于 ZAB 协议实现高可用。
  • 最佳实践:用于分布式锁、服务发现、配置管理等场景,需合理设计 ZNode 结构和 Watcher。
  • 局限性:写性能有限,大规模数据存储需选择其他方案(如 Redis 或分布式数据库)。