这是一份非常详细的Zookeeper权威指南,旨在提供全面且实用的知识。
目录
1. 背景与前世今生
1.1 起源与需求
Zookeeper 起源于雅虎研究院,是为了解决当时雅虎内部众多分布式系统(如雅虎消息代理、雅虎爬虫、雅虎内容分发网络等)所面临的共性挑战而设计的。这些挑战包括:
- 配置管理: 如何在分布式环境中集中、动态地管理配置信息。
- 命名服务: 提供统一的名称服务,帮助分布式进程找到彼此。
- 分布式同步: 实现锁、队列等同步原语,协调多个进程的操作。
- 集群管理: 监控集群节点状态,进行 Leader 选举等。
需要一个高可用、强一致性的协调服务来支撑这些上层应用。Zookeeper 应运而生。
1.2 核心设计思想
Zookeeper 的设计遵循了简单而有效的原则:
- 简单核心: 提供一个类似文件系统的树状命名空间(/path/to/znode),数据模型简单(Znode)。
- 高可用: 通过多副本(集群)实现容错。
- 强一致性: 使用 ZAB 协议保证所有副本间的数据强一致(顺序一致性)。
- 高性能: 对于读操作占主导的场景进行优化(本地读)。
- 可靠性: 一旦写入被确认,数据就会持久化,直到被显式覆盖或删除。
- 无等待: 避免慢节点阻塞整个服务(使用 Leader/Follower/Observer 架构)。
1.3 在分布式系统中的地位
Zookeeper 已成为分布式系统基础设施的基石。许多知名的开源项目都依赖它:
- Apache Hadoop (YARN ResourceManager HA, HBase Master)
- Apache Kafka (Broker 状态管理、Controller 选举、配置存储)
- Apache HBase (Master 选举、RegionServer 跟踪)
- Apache Storm (Nimbus HA, Supervisor 协调)
- Dubbo (服务注册中心) 它为这些系统提供了可靠的协调服务,是构建高可用分布式应用的关键组件。
2. 安装与部署
2.1 环境准备
- 操作系统: Linux (推荐), Windows, macOS (开发测试)。
- Java: JDK 1.8 或更高版本。确保 JAVA_HOME 环境变量设置正确。
- 下载: 从 Apache Zookeeper 官网下载稳定版本 (如 apache-zookeeper-3.7.1-bin.tar.gz)。
2.2 单机模式安装
cd apache-zookeeper-3.7.1-bin
- 复制 conf/zoo_sample.cfg 为 conf/zoo.cfg。
- 编辑 conf/zoo.cfg,设置基本参数: tickTime=2000
dataDir=/path/to/zookeeper/data # 修改为实际数据目录
clientPort=2181
bin/zkServer.cmd # Windows (双击或在命令行执行)
ls / # 查看根目录
2.3 集群模式部署 (以 3 节点为例)
initLimit=10 # Follower 连接 Leader 的超时 tick 数 (initLimit * tickTime)
syncLimit=5 # Follower 与 Leader 同步请求的超时 tick 数
dataDir=/path/to/zookeeper/data
clientPort=2181
# 集群配置,格式: server.<myid>=<server_ip>:<peer_port>:<leader_election_port>
server.1=server1:2888:3888
server.2=server2:2888:3888
server.3=server3:2888:3888
- 在 dataDir 目录下创建名为 myid 的文件。
- 文件内容为该节点对应的 server.x 中的 x (数字 ID)。例如,server1 的 myid 文件内容为 1。
- 依次在每台服务器上执行 bin/zkServer.sh start。
- 登录任意节点客户端: bin/zkCli.sh -server server1:2181
- 执行命令查看集群状态: echo stat | nc server1 2181 或使用 bin/zkServer.sh status。应能看到 Mode: leader 或 Mode: follower。
2.4 配置文件详解 (zoo.cfg)
- tickTime: 基本时间单元 (毫秒)。用于心跳和超时计算。
- dataDir: 数据快照 (Snapshot) 存储目录。
- dataLogDir: 事务日志 (Transaction Log) 存储目录 (可选,不设置则存于 dataDir)。
- clientPort: 客户端连接端口。
- initLimit: Follower 启动时,连接并同步到 Leader 的最长等待时间 (tick 数)。
- syncLimit: Leader 与 Follower 之间心跳丢失后,Leader 认为 Follower 失效的最长时间 (tick 数)。
- maxClientCnxns: 单个客户端 IP 允许的最大连接数 (默认 60)。
- autopurge.snapRetainCount: 保留的快照文件数量 (默认 3)。
- autopurge.purgeInterval: 自动清理任务间隔 (小时,默认 0 表示禁用)。
- server.x=host:port1:port2: 集群成员列表。port1 用于节点间通信 (Peer),port2 用于 Leader 选举。
2.5 启动与验证
- bin/zkServer.sh start: 启动服务 (后台)。
- bin/zkServer.sh start-foreground: 前台启动 (方便调试)。
- bin/zkServer.sh stop: 停止服务。
- bin/zkServer.sh status: 查看服务状态 (单机或集群角色)。
- bin/zkServer.sh restart: 重启服务。
- bin/zkCli.sh -server <host:port>: 连接服务并进入命令行交互界面。
3. 基础知识
3.1 数据模型:Znode
Zookeeper 的数据存储在一个分层的命名空间中,类似于文件系统的目录树结构。树中的每个节点称为 Znode。
- Znode 通过路径唯一标识,如 /services/serviceA。
- 每个 Znode 可以存储少量数据 (字节数组,通常小于 1MB)。
- 每个 Znode 维护一组状态信息 (Stat),包括版本号、时间戳等。
3.2 节点类型 (持久、临时、顺序)
- 持久节点 (Persistent):
- 创建后永久存在,除非显式删除。
- 命令: create /path data
- 临时节点 (Ephemeral):
- 生命周期与创建它的客户端会话绑定。会话结束 (客户端断开或超时),节点自动删除。
- 不能有子节点。
- 常用于表示在线状态 (如服务实例注册)。
- 命令: create -e /path data
- 顺序节点 (Sequential):
- 在创建时,Zookeeper 会在路径后追加一个单调递增的计数器 (10位数字)。如 /task/task-0000000001。
- 可以是持久的或临时的 (-s 标志)。
- 常用于实现分布式队列、公平锁。
- 命令: create -s /path data (持久顺序) / create -e -s /path data (临时顺序)
3.3 版本号 (Version)
Zookeeper 为每个 Znode 维护多个版本号:
- dataVersion: 数据内容版本。每次修改数据递增。
- cversion: 子节点版本。子节点变化 (增删) 时递增。
- aclVersion: ACL 权限版本。ACL 变更时递增。
- 这些版本号用于实现乐观锁机制。更新或删除操作可以指定预期的版本号 (set /path data <version>, delete /path <version>)。如果实际版本号不匹配,操作将失败。避免并发修改冲突。
3.4 Watcher 机制
Watcher 是 Zookeeper 实现变更通知的核心机制。
- 一次性触发: Watcher 在监听到事件并通知客户端后即被移除 (需要重新注册才能继续监听)。这是为了避免事件风暴。
- 事件类型: NodeCreated, NodeDeleted, NodeDataChanged, NodeChildrenChanged。
- 注册方式: 通过 get, exists, getChildren 等操作注册 Watcher,监听对应 Znode 的数据变化或子节点变化。
- 通知方式: Zookeeper 服务端通过客户端建立的连接将事件异步发送给客户端。
- 注意事项: Watcher 通知可能丢失 (网络问题),客户端应做好重试或主动拉取的准备。避免注册过多 Watcher 造成性能压力。
3.5 会话 (Session)
客户端通过 TCP 与 Zookeeper 服务端建立会话 (Session)。
- 会话状态: CONNECTING, CONNECTED, CLOSED, NOT_CONNECTED。
- 会话超时: 客户端需在 tickTime * syncLimit 时间内发送心跳 (Ping) 以保持会话有效。服务端也会主动向客户端发送 Ping。
- 临时节点: 临时节点的生命周期与会话绑定。会话失效 (超时或显式关闭),临时节点被删除。
- Watcher: Watcher 与会话关联。会话失效,Watcher 失效。
- 连接断开处理: Zookeeper 客户端库通常会自动重连。在重连期间,会话通常保持有效 (除非超过超时时间)。重连成功后,Watcher 需要重新注册 (客户端库通常会自动处理)。
3.6 ACL 权限控制
Zookeeper 使用 ACL (Access Control Lists) 来保证 Znode 访问的安全性。
- ACL 构成: 每个 ACL 条目由三部分组成:
- scheme: 授权模式 (如 world, auth, digest, ip, x509)。 digest 是最常用的,基于用户名密码。
- id: 模式下的具体标识 (如 world 的 id 是 anyone; digest 的 id 是 username:base64(SHA1(password)))。
- permissions: 权限位 (CRDWA – Create, Read, Delete, Write, Admin)。
- 权限:
- c (CREATE): 创建子节点。
- r (READ): 读取 Znode 数据和子节点列表。
- w (WRITE): 修改 Znode 数据。
- d (DELETE): 删除子节点。
- a (ADMIN): 设置 ACL 权限。拥有 a 权限才能修改 ACL。
- 设置 ACL: 在创建 (create) 或设置 (setAcl) Znode 时指定。
- 示例: addauth digest user1:password1 # 登录
create /secure-node \”data\” digest:user1:base64(SHA1(password1)):crwa # 创建节点并设置 ACL
getAcl /secure-node # 查看 ACL
4. 运维管理
4.1 常用命令行工具 (zkCli.sh)
zkCli.sh 是与 Zookeeper 交互的主要命令行工具。常用命令:
- ls <path> [watch]: 列出指定路径的子节点。
- get <path> [watch]: 获取指定节点的数据和状态信息 (Stat)。
- create [-s] [-e] <path> <data> [acl]: 创建节点。
- set <path> <data> [version]





