bigywater.tech
ZooKeeper · 110

ZooKeeper 与 Consul 对比

Consul 常被拿来和 ZooKeeper 比较:它既是 KV 又是服务发现。这篇不比功能清单,而是在同一台机器上起 3 个 Consul server,用与前面 ZooKeeper、etcd 同样的方法量写延迟、watch、session 与锁、健康检查、leader 切换和 KV 大小限制 —— 尤其是 session 与锁的实际耗时,和我原先的印象差别很大。

34 s
kill -9 锁持有者后,Consul 默认配置下别人拿到锁的时间(ZooKeeper 约 3 s)
6–14 s
杀掉 leader 后默认参数下写入不可用的窗口
512 KiB
Consul KV 单个值的大小上限

写延迟与 watch

实测 · 本机执行输出
  Consul:中位 5.02 ms,p99 9.11 ms
实测 · 本机执行输出
  16 线程共写 208 次;阻塞查询的 watcher 被唤醒 62 次(每次返回当时的最新值);最后看到的值 r142。阻塞查询只返回「变化后的当前状态」,中间的更新会被合并,和 ZooKeeper 的 watch 类似(第 108 篇里 etcd 的 watch 流则每个 revision 一个事件)

阻塞查询与ZooKeeper 的一次性 watch在语义上相近:都不保证每次变更都通知。

session 与锁

实测 · 本机执行输出
  lock-delay=default 15s(第 1 次):锁 key 上的 Session 在 kill -9 后 19.1 s 被清掉(session 失效);B 在 34.0 s 拿到锁
  lock-delay=default 15s(第 2 次):锁 key 上的 Session 在 kill -9 后 19.1 s 被清掉(session 失效);B 在 34.0 s 拿到锁
  lock-delay=0(第 1 次):锁 key 上的 Session 在 kill -9 后 19.1 s 被清掉(session 失效);B 在 19.1 s 拿到锁
  lock-delay=0(第 2 次):锁 key 上的 Session 在 kill -9 后 19.1 s 被清掉(session 失效);B 在 19.1 s 拿到锁

Consul 的 session 有最小 TTL(10 s),实测 kill -9 之后约 19 s 才失效(约为 TTL 的 2 倍,这是我观察到的数字,没有查文档),再叠加 lock-delay(默认 15 s,防止刚失效的锁被立即抢走)。ZooKeeper 的锁是靠会话超时(这里 3 s)释放临时节点,没有 lock-delay。这些数值都可以调(session TTL、lock-delay),我只测了默认值与 lock-delay=0。

服务健康检查

实测 · 本机执行输出
  kill -9 之前 passing 实例数 1;之后消失用时 [2.0, 2.0, 2.0] s(TTL 3 s)

和用 ZooKeeper 做服务发现相比,Consul 的健康是显式的「检查」概念(TTL、HTTP、脚本等),不是连接是否存活。

leader 切换

实测 · 本机执行输出
  默认参数:[13551, 11608, 5781] ms;raft_multiplier=1:[1633, 2026, 1958] ms

Consul 的 raft 默认参数偏保守(performance.raft_multiplier 默认 5),适合跨机房与不稳定网络;本机上调成 1 就快得多。

值的大小

实测 · 本机执行输出
  写 524288 字节 → HTTP 200 
  写 524289 字节 → HTTP 413 Request body(524289 bytes) too large, max size: 524288 bytes. See https://developer.hashic

分步演示

ZooKeeper vs Consul
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / ZooKeeper 3.9.6(brew 安装的 jar,用 java -cp 直接启动自己的实例,OpenJDK 17 Temurin,JVM 堆 128 MiB)/ 本机回环端口 7300+,数据在临时目录;默认 tickTime=2000;计时用 time.perf_counter,数字每次运行会有小幅抖动。Consul 2.0.4(releases.hashicorp.com 的 darwin_arm64 二进制)三个 server,端口 7701+,只开 HTTP;客户端是 Python http.client;lock 与 TTL 检查的持有者是独立子进程;raft_multiplier 对比各 3 次;ZooKeeper 数字引用第 79、88、108 篇(同一台机器,方法略有不同)
    • 没有验证:Consul 的 DNS 接口、多数据中心(WAN)、ACL、Connect、Consul 1.x 的行为是否与 2.0 不同、session TTL 与 lock-delay 的其它取值、网络分区下的表现、大数据量的内存占用、Consul 的许可证对使用的影响(我没有核对)
    京ICP备2026067502号-1京公网安备11010502063487号