bigywater.tech
ZooKeeper · 91

Python Kazoo 客户端

kazoo 是 Python 里最常用的 ZooKeeper 客户端。这篇不抄文档,只量你写代码时一定会撞上的行为:异常长什么样、同步和异步差多少、回调线程被阻塞会怎样、连不上怎么办、服务端重启时状态怎么变。

33 倍
异步流水线相对同步调用的吞吐
2020 ms
一个回调睡 2 秒时另一个回调被拖延的时间
LOST
中断超过会话超时后经历 SUSPENDED → LOST → CONNECTED,临时节点丢失

异常

实测 · 本机执行输出
  create 已存在       → NodeExistsError
  get 不存在          → NoNodeError
  delete 有子节点      → NotEmptyError
  set 版本不符         → BadVersionError
  临时节点下建子节点        → NoChildrenForEphemeralsError
  create 父不存在      → NoNodeError

同步与异步

实测 · 本机执行输出
  同步 307 个/s(6.53 s);异步流水线 9986 个/s(0.20 s);异步是同步的 32.6 倍

异步的好处在请求流水线那篇讲过:一个连接上请求可以连续发出,不用等上一个返回。

回调线程

实测 · 本机执行输出
  /w1 的回调睡 2 秒;/w2 在 2020 ms 后才收到回调(没有被阻塞则应该 < 50 ms)

kazoo 默认的 handler 是线程版,所有 watch 与状态监听回调共用一个线程。这也是为什么服务发现那篇里监听器里同步 create 没有成功:我观察到它没重建节点,没有查根因,但这与「回调线程不能阻塞」是一致的。

连不上

实测 · 本机执行输出
  连一个没有服务的端口 start(timeout=3):3.1 s 后抛 KazooTimeoutError;state = LOST

服务端重启与会话

实测 · 本机执行输出
  服务端 SIGTERM 停止后 1.0 s 重新启动(会话超时 3 s);服务端停止发生在 +0.5 s,重新启动完成在 +2.2 s
    listener 状态序列:[(0.4, 'SUSPENDED'), (2.3, 'CONNECTED')]
    中断期间发起的 get('/'):成功,发起后 1.5 s 返回(相对重启完成 +0.0 s)
    会话 id 不变:True;临时节点还在:True
  服务端 SIGTERM 停止后 6.0 s 重新启动(会话超时 3 s);服务端停止发生在 +0.5 s,重新启动完成在 +7.2 s
    listener 状态序列:[(0.4, 'SUSPENDED'), (12.8, 'LOST'), (13.0, 'CONNECTED')]
    中断期间发起的 get('/'):SessionExpiredError,发起后 12.0 s 返回(相对重启完成 +5.6 s)
    会话 id 不变:False;临时节点还在:False

状态含义见会话。SUSPENDED 期间发起的调用会一直等,不会立刻抛 ConnectionLoss,需要有上限时请自己设超时。

分步演示

kazoo 行为
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 / ZooKeeper 3.9.6(brew 安装的 jar,用 java -cp 直接启动自己的实例,OpenJDK 17 Temurin,JVM 堆 128 MiB)/ 本机回环端口 7300+,数据在临时目录;默认 tickTime=2000;计时用 time.perf_counter,数字每次运行会有小幅抖动。kazoo 2.11.0、Python 3.14;服务端为单节点,重启用 SIGTERM 停止 / 重新启动,不擦数据;会话超时 3 s
    • 没有验证:gevent / asyncio 的 handler、kazoo 的 SASL / TLS 配置(见第 75、77 篇的 Java 侧)、DataWatch 的 allow_missing_node 等参数的全部组合、client.retry 的各种策略
    京ICP备2026067502号-1京公网安备11010502063487号