ZooKeeper
ZooKeeper 是 Apache 开源的分布式协调服务,为分布式系统提供一致性服务,包括配置维护、域名服务、分布式同步、组服务等。
适用场景
分布式锁、配置中心、服务注册发现、Leader 选举、分布式队列。
核心概念
| 概念 | 说明 |
|---|---|
| ZNode | 数据节点,ZooKeeper 的最小数据单元 |
| Session | 客户端与服务器的会话 |
| Watcher | 监听器,监听节点变化 |
| ACL | 访问控制列表,控制节点权限 |
ZNode 类型
| 类型 | 说明 | 特点 |
|---|---|---|
| 持久节点 | 手动创建和删除 | 一直存在 |
| 临时节点 | 会话结束自动删除 | 与会话绑定 |
| 顺序节点 | 自动追加递增序号 | 用于排序 |
| 临时顺序节点 | 临时+顺序 | 分布式锁常用 |
读写机制
写请求:所有写请求转发给 Leader,由 Leader 广播给所有 Follower,超过半数同意则提交。
读请求:可从任意节点读取,但可能读到旧数据(最终一致性)。
ZAB 协议
ZAB(ZooKeeper Atomic Broadcast)是 ZooKeeper 保证数据一致性的核心协议,负责两个任务:原子广播(正常状态下同步写请求)和 崩溃恢复(Leader 故障时选举新 Leader 并同步数据)。
原子广播(两阶段提交简化版)
Leader 收到写请求
→ 生成事务 Proposal,分配单调递增的 ZXID(事务编号)
→ 广播给所有 Follower
→ 超过半数 Follower ACK 后提交(Commit)并通知各节点执行注
ZXID 的作用
ZXID(ZooKeeper Transaction ID)是事务的唯一编号,由"纪元(epoch)+ 事务序号"组成。选举时ZXID 最大的节点优先成为 Leader——它拥有最新数据,选它可减少数据同步量。
崩溃恢复(选主)
Leader 故障后进入恢复模式,过程分三步:
- 发现:各节点比较自身 ZXID,按 ZXID 大小选出候选 Leader
- 同步:新 Leader 与所有节点对比数据,把落后的节点补齐到自己的最新状态
- 广播:半数以上节点完成同步后,新 Leader 对外提供写服务
只有集群超过半数节点存活才能选出 Leader 继续服务——这是 ZooKeeper 要求奇数节点部署的根本原因,也是其保证强一致性的代价:可用性低于 AP 系统。
Watcher 监听
zk.getData("/config/app", event -> {
System.out.println("节点变化: " + event.getType());
}, null);注意
Watcher 是一次性的
触发后需要重新注册。使用 Curator 等客户端库的 Cache 机制可实现持续监听。
监听事件:NodeCreated、NodeDeleted、NodeDataChanged、NodeChildrenChanged。
分布式锁实现
基于临时顺序节点实现:
集群角色
| 角色 | 说明 |
|---|---|
| Leader | 处理写请求,事务请求唯一调度者 |
| Follower | 处理读请求,参与投票 |
| Observer | 处理读请求,不参与投票 |
常用命令
# 连接
zkCli.sh -server localhost:2181
# 创建/读取/设置/删除/列出子节点
create /node data
get /node
set /node newdata
delete /node
ls /node常见问题
| 问题 | 解决方案 |
|---|---|
| 会话超时 | 检查网络延迟;调整 Session 超时时间(默认 2 倍 tickTime);确认集群节点正常 |
| 脑裂问题 | ZAB 协议保证一致性,超过半数节点存活即可工作;生产环境建议部署奇数个节点(3、5、7) |
| Watcher 丢失 | Watcher 是一次性的,触发后需重新注册;使用 Curator 的 Cache 机制实现持续监听 |