Curator 是 Java 里事实标准的 ZooKeeper 客户端,它做的事主要是:重试、状态管理、流式 API,再加一堆现成的配方。这篇从 Maven 拉 Curator 5.7.1,量 namespace、后台调用的吞吐,以及服务端冻结(模拟长 GC)时状态机怎么走、调用与临时节点怎么恢复。
create EPHEMERAL_SEQUENTIAL 返回的路径(namespace 之内):/cfg/job-0000000001
不带 namespace 的客户端 getChildren("/"):[zookeeper, app1];getChildren("/app1/cfg"):[job-0000000001, db]
setData().withVersion(99) → BadVersionException
create 已存在 → NodeExistsException同步 324 个/s(6.17 s);inBackground 25405 个/s(0.08 s);78.3 倍
对照kazoo的结果:Java 的 inBackground 和 Python 的 create_async 都是把请求在一个连接上流水线化,服务端按批处理。
冻结发生在 +0.0 s,解冻在 +5.0 s listener 状态序列:[4.1s SUSPENDED, 5.9s RECONNECTED] 中断期间发起的 setData(retry=ExponentialBackoffRetry):成功,发起后 5.6 s 返回(相对解冻 +0.9 s) 会话 id 变了:false(旧 0x1000c96917c0002,新 0x1000c96917c0002) 会话没有变:普通临时节点一直在(true),PersistentNode 的节点在(true)
用 kill -STOP 冻结 ZooKeeper 进程来模拟「服务端不响应」(TCP 连接保持,没有重置)。客户端在 2/3 会话超时后没读到响应才判定 SUSPENDED。
冻结发生在 +0.0 s,解冻在 +12.0 s listener 状态序列:[0.0s CONNECTED, 4.1s SUSPENDED, 10.1s LOST, 12.1s RECONNECTED] 中断期间发起的 setData(retry=ExponentialBackoffRetry):成功,发起后 11.7 s 返回(相对解冻 +0.0 s) 会话 id 变了:true(旧 0x1000c96917c0003,新 0x1000c96917c0005) 解冻后,旧会话的普通临时节点在服务端消失于 +7.0 s;PersistentNode 的节点属主变成新会话于 +7.0 s(相对解冻)
LOST 是客户端自己根据会话超时算出来的:服务端冻结时它既不能通知也不能确认。因此冻结期间可能出现「客户端认为会话丢了、服务端上旧会话的临时节点还在」的一小段窗口(这里实测 0 到 7 s)—— 不要假设旧会话的临时节点在新会话建立时已经消失。