ZooKeeper 和 etcd 都是「小而强一致的协调存储」,最常被拿来比较。这篇不列特性对照表,而是在同一台机器上各起 3 个节点,在同样的 fsync 条件下量写延迟、并发写、watch 在快速更新下的语义、崩溃发现、杀 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 网关拉低,不要据此判断服务端。
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
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)