1、简述
在分布式系统中,一致性 是最重要的问题之一。ZooKeeper 作为分布式协调服务,其核心是通过 ZAB(ZooKeeper Atomic Broadcast)协议 来实现数据一致性。
ZAB 是 ZooKeeper 专门设计的一种 原子广播协议,类似于 Paxos,但更贴合 主从同步和崩溃恢复场景。
2、ZAB 算法
2.1 核心目标
ZAB 的设计目标是保证:
🔹 顺序一致性:所有事务请求(写操作)在所有节点上按相同顺序应用。
🔹 原子性:事务要么在所有节点上提交,要么不提交。
🔹 可恢复性:即使 Leader 宕机,系统仍能恢复并继续提供一致的服务。
2.2 ZAB 的工作流程
ZAB 协议有两个核心模式:
崩溃恢复(Crash Recovery)
🔹 Leader 崩溃后,集群进入恢复模式;
🔹 重新选举新的 Leader,并通过 同步阶段 确保新 Leader 与过半 Follower 数据一致。
消息广播(Message Broadcast)
🔹 在稳定状态下,Leader 接收客户端写请求;
🔹 Leader 将请求转为事务 Proposal,并发送给 Follower;
🔹 Follower 写入事务日志并返回 ACK;
🔹 当超过半数节点 ACK,Leader 提交事务并通知所有节点应用。
2.3 ZAB 与 Paxos 的区别
🔹 Paxos 更通用,解决分布式一致性问题;
🔹 ZAB 针对 ZooKeeper 进行了优化:
提供 **崩溃恢复 + 广播** 两阶段机制;
强调事务的顺序广播;
使用单 Leader 简化协议。
2.4 ZAB 协议的关键特性
崩溃恢复保障
通过选举和数据同步,保证新 Leader 一定包含所有已提交事务。
广播保障
🔹 提案必须经过半数以上确认;
🔹 Leader 负责保证顺序一致性。
数据同步策略
🔹 Leader 向 Follower 下发最新 Proposal;
🔹 Follower 回放事务日志,保证状态一致。
3、实践样例
虽然 ZAB 在 ZooKeeper 内部实现,我们无法直接“调用 ZAB”,但可以写一个 Java Demo 来模拟 主从事务提交。
3.1. 定义事务 Proposal
class Proposal {
private final String data;
private final long zxid; // ZooKeeper事务ID
public Proposal(long zxid, String data) {
this.zxid = zxid;
this.data = data;
}
public long getZxid() { return zxid; }
public String getData() { return data; }
}
3.2 模拟 Leader
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
class Leader {
private final List<Follower> followers;
private final AtomicLong zxid = new AtomicLong(0);
public Leader(List<Follower> followers) {
this.followers = followers;
}
public void broadcast(String data) {
long newZxid = zxid.incrementAndGet();
Proposal proposal = new Proposal(newZxid, data);
// 发送提案给所有Follower
int ackCount = 1; // Leader 自己默认 ACK
for (Follower f : followers) {
if (f.receiveProposal(proposal)) {
ackCount++;
}
}
// 半数以上确认才提交
if (ackCount > (followers.size() + 1) / 2) {
commit(proposal);
} else {
System.out.println("Proposal " + newZxid + " commit failed.");
}
}
private void commit(Proposal proposal) {
System.out.println("Leader commit: " + proposal.getData());
for (Follower f : followers) {
f.commit(proposal);
}
}
}
3.3 模拟 Follower
import java.util.*;
class Follower {
private final List<Proposal> log = new ArrayList<>();
// 接收 Proposal 并写日志
public boolean receiveProposal(Proposal proposal) {
log.add(proposal);
System.out.println("Follower received proposal: " + proposal.getData());
return true; // 模拟成功ACK
}
// Leader 提交后应用事务
public void commit(Proposal proposal) {
System.out.println("Follower commit: " + proposal.getData());
}
}
3.4 测试 Demo
public class ZABDemo {
public static void main(String[] args) {
List<Follower> followers = Arrays.asList(new Follower(), new Follower(), new Follower());
Leader leader = new Leader(followers);
leader.broadcast("Order-Create: #1001");
leader.broadcast("Order-Pay: #1001");
leader.broadcast("Order-Ship: #1001");
}
}
运行结果示例
Follower received proposal: Order-Create: #1001
Follower received proposal: Order-Create: #1001
Follower received proposal: Order-Create: #1001
Leader commit: Order-Create: #1001
Follower commit: Order-Create: #1001
Follower commit: Order-Create: #1001
Follower commit: Order-Create: #1001
...
可以看到,Leader 发起提案,Follower 写日志并 ACK,超过半数后事务被提交。
4、应用场景
ZAB 算法在 ZooKeeper 中是核心协议,广泛用于:
🔹 分布式协调(服务注册、分布式锁)
🔹 元数据存储(Kafka、Hadoop 依赖 ZooKeeper)
🔹 选主机制(如 ElasticSearch Master 选举)
5、总结
🔹 ZAB 是 ZooKeeper 专属一致性协议,实现了原子广播;
🔹 与 Paxos 相比,ZAB 更关注 主从复制与事务顺序;
🔹 通过 崩溃恢复 + 消息广播 两种模式,确保数据一致性;
🔹 在分布式系统中,它是保证一致性的重要基础。