ZooKeeper 有哪些典型的应用场景?
Apache ZooKeeper 是一个分布式的、开源的分布式应用程序协调服务。它提供了一组简单的原语(如数据节点 ZNode、Watcher 监听机制),允许开发者构建更复杂的分布式功能。
以下是 ZooKeeper 最典型的 6 大应用场景,以及其背后的实现原理:
1. 统一配置管理 (Configuration Management)
这是最常见的使用场景。在分布式系统中,几十上百台服务器往往需要共享相同的配置(如数据库地址、Redis 配置、Feature Flag 开关)。
- 痛点: 如果配置写在本地文件,修改配置需要逐台登录服务器修改并重启,效率极低且容易出错。
- ZK 解决方案:
- 将配置信息写入 ZooKeeper 的某个 ZNode(例如
/config/db)。 - 所有客户端(服务器)启动时读取该节点,并注册一个 Watcher。
- 当管理员修改了
/config/db的数据,ZooKeeper 会通知所有注册了 Watcher 的客户端。 - 客户端收到通知后,重新获取最新配置并动态应用,实现配置的热更新。
- 将配置信息写入 ZooKeeper 的某个 ZNode(例如
2. 统一命名服务 (Naming Service / Service Discovery)
在分布式架构(如微服务、RPC 框架)中,服务消费者需要知道服务提供者的 IP 和端口。
- ZK 解决方案:
- 服务注册: 服务提供者启动时,在 ZK 的特定路径下创建一个节点(例如
/services/userService/provider-1),存入自己的 IP:Port。 - 服务发现: 服务消费者启动时,读取
/services/userService下的所有子节点,获取可用列表。 - 动态感知: 消费者监听父节点
/services/userService。如果提供者宕机(会话断开),其创建的临时节点 (Ephemeral Node) 会自动删除,ZK 通知消费者更新可用列表。
- 服务注册: 服务提供者启动时,在 ZK 的特定路径下创建一个节点(例如
- 典型案例: Dubbo(早期的默认注册中心)、Spring Cloud Zookeeper。
3. 分布式锁 (Distributed Lock)
在单机环境下,我们可以用 Java 的 synchronized 或 ReentrantLock;但在多机环境下,需要跨进程/跨机器的锁来保证数据一致性。
- ZK 解决方案:
- 排他锁: 多个客户端尝试创建同一个临时节点(如
/lock)。只有一个能创建成功并获得锁,其他的注册 Watcher 等待释放。 - 时序锁(公平锁): 客户端在
/lock下创建临时顺序节点(如/lock/seq-001,/lock/seq-002)。- 客户端判断自己是不是序号最小的节点。如果是,获得锁。
- 如果不是,监听比自己小 1 号的节点(避免惊群效应)。当前一个节点删除时,自己获得锁。
- 排他锁: 多个客户端尝试创建同一个临时节点(如
- 特点: 可靠性高(强一致性),但性能不如 Redis 分布式锁。
4. 集群管理与 Master 选举 (Cluster Management & Leader Election)
在主从架构(Master-Slave)中,需要确保任何时刻只有一个 Master 负责写操作,且 Master 挂掉后能自动选出新的 Master(高可用 HA)。
- ZK 解决方案:
- 选举: 所有从节点尝试去创建同一个临时节点(例如
/master)。创建成功的成为 Master。 - 容灾: 其他节点监听
/master。如果 Master 宕机,临时节点消失,ZK 通知其他节点,其他节点再次发起抢占,产生新 Master。 - 节点监控: 利用临时节点,可以实时监控集群中有多少机器在线(机器上线创建节点,下线自动删除)。
- 选举: 所有从节点尝试去创建同一个临时节点(例如
- 典型案例: Hadoop HDFS (NameNode HA), HBase (HMaster), Kafka (Controller 选举)。
5. 分布式队列 (Distributed Queue)
虽然 ZK 不适合做高吞吐的消息队列(如 Kafka),但适合做控制类的队列。
- FIFO 队列: 利用顺序节点,生产者创建节点,消费者按序号顺序处理。
- 分布式屏障 (Barrier): 类似于 Java 的
CyclicBarrier。- 创建一个父节点
/barrier。 - 所有子任务启动时在下面创建子节点。
- 所有任务监听父节点的子节点数量。当子节点数量达到 N 个时,代表所有任务都就绪,同时开始执行下一步。
- 创建一个父节点
6. 负载均衡 (Load Balancing)
这是一个软负载均衡的概念。
- ZK 解决方案:
- 服务提供者将自己的负载信息(如连接数、CPU 使用率)写入 ZNode。
- 客户端在选择服务节点时,读取这些信息,根据算法选择负载较低的节点进行连接。
- 注:由于 ZK 写性能有限,不建议频繁更新高吞吐的负载信息,通常用于简单的轮询或静态权重分配。
总结:什么时候该用 ZooKeeper?
ZooKeeper 的核心价值在于 CP(一致性 + 分区容错性)。
- 适合: 数据量小(元数据)、读多写少、对数据一致性要求极高、需要实时感知的场景。
- 不适合: 存储海量数据、高频写入(写性能是瓶颈)、作为大规模的消息队列数据存储。