bigywater.tech
ZooKeeper · 108

ZooKeeper 与 etcd 对比

ZooKeeper 和 etcd 都是「小而强一致的协调存储」,最常被拿来比较。这篇不列特性对照表,而是在同一台机器上各起 3 个节点,在同样的 fsync 条件下量写延迟、并发写、watch 在快速更新下的语义、崩溃发现、杀 leader 的窗口和单值大小。注意客户端协议不同带来的偏差,吞吐只作粗略参考。

12 vs 208
快速更新时 ZooKeeper 回调数 vs etcd 事件数(etcd 每个 revision 一个事件)
5.1 vs 7.0 ms
写延迟中位(都由一次 fsync 主导)
421–1122 vs 1053–1349 ms
杀 leader 后写入不可用的窗口

写延迟

实测 · 本机执行输出
  ZooKeeper:中位 5.05 ms,p99 9.81 ms;etcd:中位 6.98 ms,p99 20.93 ms(etcd 走 HTTP/JSON 网关,每次请求多一点编解码开销;ZooKeeper 用 kazoo 的二进制协议)

并发写

实测 · 本机执行输出
  ZooKeeper 3186 次/s;etcd 1191 次/s(同一台机器、同一块磁盘、6 个服务端进程;客户端协议不同,数字只能粗略对比)

ZooKeeper 的写吞吐受 leader 的单线程提交与 fsync 限制(见延迟与吞吐)。这里 etcd 的数字被 HTTP 网关拉低,不要据此判断服务端。

watch 语义

实测 · 本机执行输出
  ZooKeeper(DataWatch;用 set_async 一次性发出 200 次写):收到 12 次回调,最后值 r199;etcd(watch 流;16 个线程并发共写 208 次):收到 208 个事件(应为 208,每个 revision 一个)

ZooKeeper 的 watch 是一次性的,etcd 的 watch 是带 revision 的持续流。需要「不漏任何变更」的场景(例如 Kubernetes 的 controller),etcd 的模型更合适;只关心最终状态的配置推送,两者都够用。

崩溃发现

实测 · 本机执行输出
  ZooKeeper(会话超时 3 s):[2.8, 2.4, 3.4] s;etcd(租约 TTL 3 s):[2.7, 2.9, 2.9] s

leader 切换

实测 · 本机执行输出
  ZooKeeper(tickTime=1000):[421, 887, 1122, 745] ms;etcd(默认 heartbeat 100 ms / election 1000 ms,客户端单次请求超时 0.25 s,所以时间窗的精度约 0.25 s):[1349, 1053, 1338, 1337] ms

ZooKeeper 的数字对照Leader 重选举那篇(那里连的不是 follower,窗口更短)。

值的大小

实测 · 本机执行输出
  etcd 写 1.0 MiB → OK
  etcd 写 1.4 MiB → OK
  etcd 写 2.0 MiB → HTTP 429 grpc: received message larger than max (2097163 vs. 2097152)

分步演示

ZooKeeper vs etcd
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / ZooKeeper 3.9.6(brew 安装的 jar,用 java -cp 直接启动自己的实例,OpenJDK 17 Temurin,JVM 堆 128 MiB)/ 本机回环端口 7300+,数据在临时目录;默认 tickTime=2000;计时用 time.perf_counter,数字每次运行会有小幅抖动。ZooKeeper 3.9.6 三节点(forceSync=yes,tickTime=1000)与 etcd 3.7.2 三节点(默认配置,HTTP/JSON gRPC 网关),同一台机器、同一块磁盘、6 个服务端进程;ZooKeeper 客户端 kazoo,etcd 客户端是 Python http.client(keep-alive);每项只测了一轮
    • 没有验证:跨机房延迟、etcd 的 gRPC 原生客户端下的吞吐、etcd 的压缩与 defrag、大数据量(百万 key)下的内存与恢复时间、etcdctl check perf 导致 panic 的原因、ZooKeeper 与 etcd 在网络分区下的行为差异(见第 47 篇只验证了 ZooKeeper)
    京ICP备2026067502号-1京公网安备11010502063487号