60 秒回答模板

ZooKeeper 分布式锁通常在固定锁目录下创建临时顺序节点。客户端创建节点后读取 children 并排序,如果自己的序号最小就获得锁;否则只监听前一个序号节点。前驱节点删除后收到 watcher 通知,再重新读取 children 判断自己是否最小。锁释放是删除自己的临时节点;客户端崩溃或会话过期时临时节点自动删除。这个方案靠顺序节点形成排队,靠监听前驱减少惊群,靠会话语义处理客户端故障,但仍要处理连接断开、创建成功响应丢失、watcher 一次性触发和业务侧 fencing。

考点 核心机制与工程取舍
难度 中高频面试题
回答目标 按定义、机制、场景讲清楚

深入解析

01

临时顺序节点把竞争变成排队

每个客户端在锁目录下创建 `lock-0000001` 这类临时顺序节点,序号由 ZooKeeper 分配,天然形成先后顺序。序号最小者进入临界区。

02

等待者只监听前驱节点

如果自己不是最小节点,就找到比自己小的最大节点并 watch 它。前驱删除时只唤醒一个后继,避免所有等待者同时被唤醒。

03

收到通知后必须重新判断

Watcher 是一次性的,而且通知只代表前驱发生变化,不代表自己已经获得锁。正确流程是收到通知后重新读取 children、排序、判断自己是否最小。

04

会话语义决定锁释放

短暂连接断开不一定释放锁,session timeout 后临时节点才会删除。业务执行时间、GC STW 和网络隔离都可能影响锁持有安全,要设置合理会话超时。

05

异常路径要能恢复

创建节点成功但响应丢失时,客户端应按请求 GUID 或节点前缀查找自己已创建的节点,避免重复入队。强写入场景同样可以配 fencing token 防旧会话继续写。

易错点

  • 所有客户端都 watch 锁根节点,造成惊群。
  • 收到 watcher 通知后不重新判断自己是否最小。
  • 把连接断开等同于会话过期,误判锁释放时机。
  • 忽略创建节点成功但响应丢失导致重复排队的问题。

面试官追问

为什么监听前一个节点?

这样每次释放锁只唤醒下一个候选者,减少惊群,并保持按顺序节点排队的公平性。

连接断开锁会马上释放吗?

不会。只有会话过期后临时节点才删除。短断线期间客户端可能还持有锁,这也是设置 session timeout 和业务超时的原因。

Watcher 通知后能直接执行业务吗?

不能。Watcher 一次性触发且可能合并事件,收到通知后必须重新查询 children 判断自己是否最小。

ZK 锁和 Redis 锁主要区别是什么?

ZK 更强调一致性、排队和会话语义,适合强协调;Redis 更轻量、性能高,但主从切换和租约安全要额外处理。