bigywater.tech
ZooKeeper · 44

ZAB 与 Raft 的区别

ZAB 和 Raft 都是「leader + 多数派」的协议,有什么区别?这篇不比较论文,而是各起一个真实集群:ZooKeeper 3 节点和 etcd 3 节点,测读语义和 leader 故障后的写中断,看实际表现的差异。

303 / 3000
etcd serializable 读(follower 本地)读到旧值的次数;线性一致读为 0
0 / 3000
ZooKeeper 本地读我没有复现出旧读(不代表不会发生)
2030 ms vs 445 ms
leader 被杀后写中断:etcd vs ZooKeeper(各自默认配置)

ZooKeeper 的本地读

实测 · 本机执行输出
  不调用 sync:读到旧值 0 / 3000 次;每次读之前先 sync():读到旧值 0 / 3000 次

ZooKeeper 文档说 follower 上的读可能落后于最新写(顺序一致而不是线性一致),sync() 用来补救。我在单机多进程环境下没能复现旧读,所以这里只能报告「没观察到」。

etcd 的读

实测 · 本机执行输出
  线性一致读(默认):读到旧值 0 / 3000 次;serializable 读(follower 本地):读到旧值 303 / 3000 次

etcd 通过 JSON HTTP 网关访问(serializable: true 选择本地读)。

leader 故障后的写中断

实测 · 本机执行输出
  第 1 次:写不可用 2030 ms;raftTerm 2 → 3
  第 2 次:写不可用 2039 ms;raftTerm 3 → 4
  第 3 次:写不可用 1784 ms;raftTerm 4 → 5
  第 4 次:写不可用 2037 ms;raftTerm 5 → 6
  第 5 次:写不可用 1024 ms;raftTerm 6 → 7
  etcd 写不可用中位 2030 ms(最小 1024 / 最大 2039);对照 ZooKeeper 第 36 篇的中位约 445 ms

两个系统的默认超时不同(etcd 选举超时 1000 ms、心跳 100 ms;ZooKeeper tickTime 2000 ms),调小之后差距会变。更完整的 etcd 对比见第 108 篇。

分步演示

ZAB 与 Raft
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / ZooKeeper 3.9.6(brew 安装的 jar,用 java -cp 直接启动自己的实例,OpenJDK 17 Temurin,JVM 堆 128 MiB)/ 本机回环端口 7300+,数据在临时目录;默认 tickTime=2000;计时用 time.perf_counter,数字每次运行会有小幅抖动。etcd 3.7.2(brew 安装)3 节点集群,端口 7600+,默认选举配置,通过 HTTP JSON 网关读写;测试都是同一台机器上的 3 个进程
    • 没有验证:两个协议在日志复制、成员变更、快照上的差异(只比较了读语义与故障恢复)、更大的集群、网络分区下的表现、etcd 调小选举超时后的结果
    京ICP备2026067502号-1京公网安备11010502063487号