ZooKeeper 分布式锁实战
ZooKeeper 系列 · 第 3/5 篇
上一篇:《ZooKeeper 客户端与经典应用场景》 · 下一篇:《ZooKeeper Leader 选举源码要点》
开头:跨 JVM 的互斥,不能再用 synchronized
单体里 synchronized / ReentrantLock 管得住一个进程内的线程;微服务多实例、多机部署时,库存扣减、订单幂等等场景需要跨进程的互斥。主流方案:数据库唯一索引、Redis(Redisson)、ZooKeeper(Curator InterProcessMutex)。本篇对比思路并落地 ZK 锁与服务注册发现。

一、分布式锁方案对比
| 方案 | 特点 |
|---|---|
| 数据库 | 唯一索引 / 悲观行锁;实现简单,性能与锁表风险差 |
| Redis | 高性能,需处理过期、续期、主从切换下的安全性 |
| ZooKeeper | 临时顺序节点 + 强一致;可靠、可重入(Curator);创建/删除节点开销较大 |

数据库思路
利用唯一索引插入锁记录;释放则 delete。问题:DB 压力大、无天然阻塞等待、死锁与超时需额外设计。

二、ZooKeeper 锁设计
思路一:临时节点
在 /lock 创建 EPHEMERAL 节点,成功者持锁;会话结束节点消失。
问题:大量客户端 watch 同一节点,删除时惊群——仅一人获锁却通知全员。

思路二:临时顺序节点(推荐)
在 /lock 下创建 EPHEMERAL_SEQUENTIAL,如 /lock/0000000001;序号最小者持锁,其余 watch 前一个节点,形成公平队列。

三、Curator InterProcessMutex
生产勿手写:使用 curator-recipes 的 InterProcessMutex(可重入、阻塞、会话失效释放锁)。
InterProcessMutex lock = new InterProcessMutex(client, "/locks/order");
try {
if (lock.acquire(10, TimeUnit.SECONDS)) {
// 临界区
}
} finally {
lock.release();
}优劣:
- 优点:高可用、可重入、避免失效死锁(临时节点 + session)
- 缺点:性能低于 Redis;高并发写锁不推荐,一致性要求高、并发适中的场景更合适
四、基于 ZK 的服务注册与发现
ZK 天然适合注册中心:Provider 在约定路径写临时节点(地址 + 元数据),Consumer watch 子节点列表,上下线实时感知。

优点:高可用(多实例)、强一致视图、Watcher 实时性。
缺点:写多时性能不如 Nacos/Consul 等专用注册中心;大规模集群需评估。
Spring Cloud Zookeeper
父 POM 指定 Spring Boot + Spring Cloud 版本(注意兼容矩阵):

依赖 spring-cloud-starter-zookeeper-discovery,排除传递的旧 zookeeper,显式引入与 Server 匹配的 zookeeper 3.8.0:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.8.0</version>
</dependency>application.yml:
spring:
cloud:
zookeeper:
connect-string: localhost:2181
discovery:
instance-host: 127.0.0.1Feign 调用示例:/user/findOrderByUserId/{id} 经注册发现路由到 order 服务。
核心入口类:ZookeeperDiscoveryClientConfiguration。
小结
- 公平 ZK 锁:临时顺序节点 + watch 前驱;用 InterProcessMutex 即可。
- 注册中心:临时节点表示实例,适合中小规模、强一致元数据场景。
- 下一篇从集群内部 Leader 选举源码视角理解 ZK 自身高可用。