临时顺序节点(EPHEMERAL_SEQUENTIAL)天然融合“先来先得”与“宕机自动释放”:临时性保障断连即删锁,顺序性生成唯一递增编号形成队列;客户端仅监听前驱节点,避免惊群效应,唤醒精准、资源消耗低。

为什么用临时顺序节点做排队锁
临时顺序节点(EPHEMERAL_SEQUENTIAL)把“谁先来、谁先得”和“宕机自动释放”两个关键能力天然融合在一起。临时性确保客户端意外断连时,锁节点立刻消失;顺序性让每个请求获得唯一递增编号,形成天然队列。相比单纯用临时节点抢锁(易引发惊群效应),顺序节点只监听前一个节点,唤醒精准,资源消耗低。
锁的创建与排队逻辑
所有客户端统一在同一个持久父节点下(如 /locks/order-pay)创建临时顺序子节点,例如:
– Client A → /locks/order-pay/lock-0000000001
– Client B → /locks/order-pay/lock-0000000002
– Client C → /locks/order-pay/lock-0000000003
每个客户端创建后立即获取该路径下全部子节点列表,并按序号排序。只有排在第一位的节点才视为持锁成功;其余节点则监听自己序号减一的那个节点(即前驱节点)的删除事件。
锁获取与释放的关键动作
获取锁流程:
- 调用
create("/locks/xxx/lock-", EPHEMERAL_SEQUENTIAL)创建节点,拿到完整路径 - 执行
getChildren("/locks/xxx", true)获取子节点列表并排序 - 若自身节点排第一,直接进入业务逻辑;否则注册 Watcher 监听前驱节点
- 收到 Watcher 通知后,重新检查是否已成最小节点(防止网络延迟或重复通知)
释放锁方式:
- 正常退出:主动删除自己创建的临时节点
- 异常崩溃:ZooKeeper 检测会话超时,自动清理节点,触发前驱监听者重检
- 无需手动续期或心跳保活,由会话机制兜底
实战中容易踩的坑
节点路径必须用持久父节点(PERSISTENT),不能误设为临时——否则父节点消失会导致整个锁体系失效。
Watcher 是一次性触发,每次监听后需在回调中重新注册,否则后续变更无法感知。
排序必须按字符串后缀数字解析为整数比较,避免 “10”
客户端应设置合理会话超时时间(如 30s),太短易误删,太长则故障恢复慢。


















