Go 的 ZooKeeper 客户端风格和 kazoo、Curator 很不一样:没有重试策略、没有缓存、watch 是 channel。这篇用 go-zookeeper/zk 实测它的错误值、watch、并发、Multi、自带锁,以及服务端不可用时的行为。
Create 已存在 → zk: node already exists | errors.Is(err, zk.ErrNodeExists) = true Get 不存在 → zk: node does not exist Set 用旧 version → zk: version conflict 临时节点下建子节点 → zk: ephemeral nodes may not have children FlagSequence 返回的路径 → /g/seq-0000000000 <nil>
第一次变化收到: EventNodeDataChanged /g 第二次变化(没有重新 GetW)收到: Unknown (读到零值事件:watch 的 channel 触发一次后就被关闭) 循环里重新 GetW:连续 Set 200 次,收到 170 次事件;最终值 r199
watch 的一次性语义见这一篇。Go 里每个 watch 是一个 channel,触发一次后关闭。
顺序 326 个/s(6.13 s);64 goroutine 11709 个/s(0.17 s);35.9 倍
Multi(建 /m1, 建已存在的 /m2) → zk: node already exists | /m1 存在 = false Multi(建 /m3, 建 /m4) → <nil> | /m3 = true /m4 = true
最终 200 / 200,用时 1.8 s;/glock 下现在的子节点数 0 持有锁时的锁节点名: _c_a1570903446f6a2122ed5ffffd14af4f-lock-0000000000
机制与分布式锁那篇相同。
0.0s StateConnecting 0.0s StateConnected 0.0s StateHasSession 0.9s StateDisconnected 0.9s StateConnecting 1.9s 调用 Get → zk: could not connect to a server(耗时 661 ms) 1.9s StateConnecting 2.9s StateConnecting 2.9s 调用 Get → zk: could not connect to a server(耗时 302 ms) 3.9s 调用 Get → zk: could not connect to a server(耗时 300 ms) 3.9s StateConnecting 4.9s StateConnecting 5.9s StateConnected 6.0s StateHasSession 10.6s 服务端恢复后 Get → <nil>(耗时 6 ms)
Go 客户端在服务端不可用时不阻塞等待而是立刻返回错误,调用方必须自己决定重试(带退避)。不要在没有消费事件 channel 的情况下使用:事件 channel 要有人读(我的程序里单独启了一个 goroutine 读)。我没有测不读事件 channel 会不会阻塞客户端。