七、ZooKeeper 原理与常见应用场景

一、什么是 ZooKeeper

ZooKeeper 是 Apache 基金会开源的分布式协调服务,最初由 Yahoo! 开发,后来成为 Hadoop 生态系统的核心组件。它为分布式应用提供了高效的分布式协调原语,帮助开发者解决分布式系统中的一致性问题。

简单来说,ZooKeeper 就像是分布式系统中的"调度指挥中心"——它本身不执行具体业务,但负责协调各个节点"统一行动":谁当领导、配置怎么同步、锁怎么分配、服务是否在线。

核心设计目标:

目标 说明
高可用 集群中部分节点宕机,服务仍可用
强一致 所有客户端看到的数据视图一致
顺序性 操作按发送顺序全局排序
高性能 读操作完全在内存中完成,适合读多写少场景
简单 提供类文件系统的简单数据模型,易于理解和使用

二、核心数据模型:ZNode 树

ZooKeeper 的数据模型是一棵树形命名空间,每个节点称为 ZNode,类似于文件系统中的目录和文件。

/                          ← 根节点
├── config                 ← 配置信息
│   ├── db_url
│   └── timeout
├── services               ← 服务注册
│   ├── order-service
│   └── user-service
└── locks                  ← 分布式锁
    └── inventory-lock

ZNode 的关键特性:

  • 路径唯一:每个 ZNode 都有唯一的绝对路径(如 /config/db_url
  • 数据存储:每个节点可以存储少量数据(默认不超过 1MB)
  • 版本控制:每个节点都有 version(数据版本)、cversion(子节点版本)、aversion(ACL版本)
  • 元数据:包含创建时间、修改时间、数据长度等信息

ZNode 的四种类型

类型 特性 典型场景
持久节点(PERSISTENT) 创建后永久存在,除非显式删除 存储配置信息、集群元数据
临时节点(EPHEMERAL) 客户端会话断开时自动删除,不能有子节点 服务注册、分布式锁、心跳检测
持久顺序节点(PERSISTENT_SEQUENTIAL) 持久节点 + 自动追加递增序号(10位) 分布式队列、全局唯一ID生成
临时顺序节点(EPHEMERAL_SEQUENTIAL) 临时节点 + 自动追加递增序号 公平分布式锁、分布式队列

关键理解:临时节点的生命周期绑定客户端会话,会话超时(sessionTimeout)后自动删除。这保证了异常情况下的自动清理,避免死锁和僵尸节点。

三、集群架构与角色分工

ZooKeeper 通常以**集群模式(Ensemble)**部署,一般使用 3、5 或 7 台服务器(奇数台,保证过半原则)。集群中有三种角色:

三种角色

角色 职责 数量
Leader 唯一写入口,分配全局ZXID,广播事务提案,协调提交 1个
Follower 参与选举投票,响应Leader提案,处理读请求,转发写请求 多个
Observer 同步数据,处理读请求,但不参与投票和提案,用于扩展读性能 可选

为什么只有 Leader 能写?

ZooKeeper 采用主从架构,写操作全部由 Leader 处理,这样可以保证所有写操作的全局顺序一致性。Follower 只负责投票确认和响应读请求。

四、ZAB 协议:强一致性的核心

ZAB(ZooKeeper Atomic Broadcast) 是 ZooKeeper 实现强一致性的核心协议,专为 ZooKeeper 设计。它有两种运行模式:

4.1 消息广播模式(正常状态)

当集群存在稳定 Leader 时,写请求处理流程如下:

客户端写请求 → Leader 生成 Proposal(分配全局 ZXID)
    → 广播给所有 Follower
    → Follower 写入本地事务日志并返回 ACK
    → Leader 收到过半 ACK 后发送 COMMIT
    → Follower 提交事务
    → Leader 响应客户端

核心要点:

  • ZXID:64位全局事务ID,高32位是 epoch(Leader任期号),低32位是事务计数器
  • 过半原则:写操作需超过半数(N/2+1)节点确认才提交,保证一致性的同时容忍部分节点宕机
  • 两阶段提交:先持久化(Proposal),再提交(Commit),确保原子性

4.2 崩溃恢复模式(Leader 宕机)

当 Leader 失效时,触发 Leader 选举:

  1. 所有节点进入 Looking 状态
  2. 每个节点先投自己一票,广播投票信息(包含自己的 ZXID 和 server_id)
  3. 选举规则:ZXID 大的优先(数据最新),ZXID 相同则 server_id 大的优先
  4. 获得过半投票的节点成为新 Leader
  5. 新 Leader 与 Follower 同步数据,集群恢复正常

五、Watch 机制:事件驱动通知

Watch 机制是 ZooKeeper 实现实时感知的基础。客户端可以在 ZNode 上注册 Watcher,当节点发生变化时,服务端会一次性推送通知

支持监听的事件类型:

事件类型 触发条件
NodeCreated 节点被创建
NodeDeleted 节点被删除
NodeDataChanged 节点数据变更
NodeChildrenChanged 子节点列表变更

Watch 机制的特点:

  • 一次性触发:Watcher 触发后自动失效,需要持续监听必须重新注册
  • 轻量高效:避免客户端轮询,降低网络开销
  • 异步通知:服务端主动推送,实时性强

六、常见应用场景

6.1 分布式锁

分布式锁是 ZooKeeper 最经典的应用场景。利用临时顺序节点 + Watch实现公平的分布式锁:

核心流程:

  1. 客户端在 /lock 下创建临时顺序节点(如 lock-0000000001
  2. 获取 /lock 下所有子节点,判断自己的序号是否最小
  3. 如果最小,获得锁;否则,Watch 前一个节点(注意:不是 Watch 所有节点,避免"羊群效应")
  4. 前一个节点删除后收到通知,重新检查自己是否最小
  5. 释放锁:删除自己的节点,或会话断开后临时节点自动删除

优势:

  • 临时节点保证客户端崩溃后锁自动释放,避免死锁
  • 顺序节点保证锁获取的公平性
  • Watch 机制保证锁释放后立即通知等待者

6.2 配置中心

将配置信息存储在 ZooKeeper 的持久节点上,所有服务实例通过 Watch 机制监听配置变更,实现配置的动态更新

/config/database/url    → 数据库连接地址
/config/database/pool   → 连接池大小
/config/feature/switch  → 功能开关

工作流程:

  1. 配置管理员更新 ZooKeeper 上的配置节点
  2. ZooKeeper 向所有 Watch 该节点的客户端推送变更通知
  3. 各服务收到通知后,拉取最新配置并生效

适用场景: 配置项少、变更频率低的场景。如果配置量大、变更频繁,建议使用 Apollo 或 Nacos。

6.3 服务注册与发现

服务提供者启动时在 ZooKeeper 上创建临时节点,服务消费者通过 Watch 监听服务列表变化。

/services/order-service/instance-1    → 192.168.1.10:8080
/services/order-service/instance-2    → 192.168.1.11:8080

核心优势:

  • 服务实例宕机后,会话失效,临时节点自动删除
  • 消费者通过 Watch 立即感知服务下线,无需轮询
  • 服务上线时,消费者自动获取新实例地址

Dubbo、Kafka(旧版)、HBase 等大数据组件都依赖 ZooKeeper 实现服务注册与发现。

6.4 Master 选举(Leader 选举)

在需要单主节点的分布式系统中,利用 ZooKeeper 实现自动的 Master 选举:

实现方式:

  • 所有服务实例竞争创建同一个临时节点(如 /master
  • 创建成功的实例成为 Master
  • 其他实例 Watch 该节点
  • Master 宕机后,临时节点自动删除,触发重新选举

典型应用: Kafka Controller 选举、HBase Master 选举、Flink JobManager 高可用。

6.5 分布式队列 / 屏障

  • 分布式队列:利用顺序节点实现 FIFO 队列,消费者按顺序获取任务
  • 分布式屏障:所有参与者创建临时节点,当节点数达到阈值时"打开屏障",实现并行任务的汇合点

七、分布式安装部署

1. 集群规划

在已有的hadoop1、hadoop2、hadoop3上部署Zookeeper 3.7.2。

2. 下载安装

  1. 下载地址:https://zookeeper.apache.org/releases

在这里插入图片描述

  1. 下载完后上传到 /opt/software目录,再 tar 解压到 /opt/module
cd /opt/software
tar -zxvf apache-zookeeper-3.7.2-bin.tar.gz -C /opt/module/

在这里插入图片描述

3. 配置和分发

  1. 创建zookeeper的数据目录 zkData
cd apache-zookeeper-3.7.2-bin/
mkdir zkData

在这里插入图片描述

  1. 在 zkData目录下创建一个 myid 文件,文件内容为zookeeper服务器编号:
echo 1 > zkData/myid   # 几号服务器就修改数字为几
  1. 重命名/opt/module/apache-zookeeper-3.7.2-bin/conf目录下的zoo_sample.cfg为zoo.cfg
cd conf
mv zoo_sample.cfg zoo.cfg
vim zoo.cfg

修改 dataDir 项为:

dataDir=/opt/module/apache-zookeeper-3.7.2-bin/zkData

文件末尾添加:

#######################cluster##########################
server.1=hadoop1:2888:3888
server.2=hadoop2:2888:3888
server.3=hadoop3:2888:3888

在这里插入图片描述

  1. 分发 Zookeeper:
cd /opt/module
xsync apache-zookeeper-3.7.2-bin
  1. 在其它机器hadoop2、hadoop3上修改 myid 中的内容为 2、3

4. 集群启停脚本

  1. /home/hadoop/bin 目录下创建脚本
cd ~/bin
vim zk.sh

输入如下内容:

#!/bin/bash
case $1 in
"start"){
	for i in hadoop1 hadoop2 hadoop3
	do
        echo ---------- zookeeper $i 启动 ------------
		ssh $i "/opt/module/apache-zookeeper-3.7.2-bin/bin/zkServer.sh start"
	done
};;
"stop"){
	for i in hadoop1 hadoop2 hadoop3
	do
        echo ---------- zookeeper $i 停止 ------------    
		ssh $i "/opt/module/apache-zookeeper-3.7.2-bin/bin/zkServer.sh stop"
	done
};;
"status"){
	for i in hadoop1 hadoop2 hadoop3
	do
        echo ---------- zookeeper $i 状态 ------------    
		ssh $i "/opt/module/apache-zookeeper-3.7.2-bin/bin/zkServer.sh status"
	done
};;
esac
  1. 增加执行权限
chmod +x zk.sh
zk.sh start
zk.sh stop

在这里插入图片描述

八、总结

ZooKeeper 的核心价值可以用一句话概括:状态存储 + 事件通知 + 强一致性保证

核心能力 支撑的应用场景
临时节点 服务注册与发现、Master 选举、分布式锁(自动清理)
顺序节点 公平分布式锁、分布式队列、全局唯一ID
Watch 机制 配置变更通知、服务上下线感知、锁状态监听
ZAB 协议 保证所有场景下的数据一致性

技术选型建议:

场景 推荐方案
强一致性要求高(金融、选举) ZooKeeper(CP模型)
高并发场景(限流、缓存锁) Redis(AP模型,性能更好)
服务注册发现(新项目) Nacos、Consul(ZooKeeper Watch 有数量限制)
大数据生态(Hadoop/HBase/Kafka) ZooKeeper(生态成熟)

参考资源:

  • Apache ZooKeeper 官方文档
© 版权声明

相关文章