后端与运维
单机 synchronized 不管用?一文搞懂基于 Redis 与 ZooKeeper 的分布式锁
一个秒杀系统,库存只有 100 件,10000 个人同时抢。
单机时代,写 synchronized 或 ReentrantLock 就能保证同一时刻只有一个线程修改库存。
但系统上线后变成了 3 台服务器。synchronized 只能锁住同一台 JVM 里的线程——服务器 A 的线程 1 和服务器 B 的线程 2,可以同时扣库存。 库存从 100 变成了 -50。
单机锁锁不住分布式环境下的资源竞争。 你需要一把”跨服务器的锁”——分布式锁。
白话版

单机锁和分布式锁的区别,就像宿舍插销和小区公共健身房的电子钥匙箱:
- 单机锁(synchronized) — 宿舍卫生间的插销,只能锁住同一个房间的人
- 分布式锁(Redis / ZooKeeper) — 小区公共健身房的电子钥匙箱。不同栋楼(不同服务器)的人要用同一个设施,都得去中央钥匙箱申请唯一钥匙,用完归还
所有服务器都去同一个”中央钥匙箱”申请锁,谁拿到锁,谁就有权限操作共享资源。
基于 Redis 的分布式锁
Redis 实现分布式锁,靠的是 SETNX 命令——“SET if Not eXists”(不存在才设置)。
最简单的实现
import redis
cache = redis.Redis()
def deduct_stock(product_id, quantity):
lock_key = f"lock:stock:{product_id}"
# SETNX:如果 key 不存在就设置,存在则返回失败
# NX = 只在不存在时设置
# EX = 过期时间(秒),防止死锁
locked = cache.set(lock_key, "1", nx=True, ex=10)
if not locked:
# 没拿到锁,说明有其他线程在操作
return False # 返回失败,让调用方重试或等待
try:
# 拿到锁,安全操作共享资源
stock = cache.get(f"stock:{product_id}")
if not stock or int(stock) < quantity:
return False
cache.decrby(f"stock:{product_id}", quantity)
return True
finally:
# 释放锁
cache.delete(lock_key)
这个实现有什么问题?
| 问题 | 场景 | 后果 |
|---|---|---|
| 锁过期 | 业务执行超过 10 秒,锁自动释放了 | 其他线程拿到锁,同时操作,数据不一致 |
| 误删锁 | 线程 A 的锁过期了,线程 B 拿到了锁,A 执行完了去删锁 | 把 B 的锁删了,B 的锁白拿 |
| 死锁 | 获取锁后程序崩溃,没执行到 finally 释放锁 | 锁永远不释放 |
进阶实现:Redisson 看门狗机制

Redis 官方推荐的 Java 客户端 Redisson,内置了看门狗(Watchdog) 机制解决锁过期问题:
// 使用 Redisson 的分布式锁
@Autowired
private RedissonClient redisson;
public boolean deductStock(String productId, int quantity) {
RLock lock = redisson.getLock("lock:stock:" + productId);
try {
// 尝试加锁,最多等 5 秒,拿到锁后 30 秒自动释放
if (lock.tryLock(5, 30, TimeUnit.SECONDS)) {
// 看门狗机制:每 10 秒自动续期,锁不会"过期被误删"
// 只要业务没执行完,锁就一直有效
int stock = getStock(productId);
if (stock < quantity) {
return false;
}
deductStock(productId, quantity);
return true;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
// 释放锁(同时会关闭看门狗)
lock.unlock();
}
return false;
}
看门狗的工作原理:
线程 A 获取锁,锁超时 30 秒
→ 看门狗启动,每 10 秒检查一次
→ 如果线程 A 还在运行,把锁的过期时间重置为 30 秒
→ 线程 A 执行完毕,释放锁,看门狗也关闭
线程 A 获取锁,锁超时 30 秒
→ 看门狗启动
→ 线程 A 代码有 bug,卡住了(死循环、无限等待)
→ 看门狗不断续期,但锁永远不释放
→ 其他线程永远拿不到锁
→ 这个问题怎么解决?别担心,看门狗续期也有上限
→ 如果线程 A 彻底挂了(JVM 崩溃),看门狗也停了,锁自然过期
基于 ZooKeeper 的分布式锁

ZooKeeper 实现分布式锁的原理和 Redis 不同,它用的是临时顺序节点(Ephemeral Sequential Node):
// ZooKeeper 分布式锁的伪代码
public class ZkDistributedLock {
private ZooKeeper zk;
private String lockPath = "/locks/resource";
public boolean tryLock() {
// 1. 在 /locks/resource 下创建临时顺序节点
// 比如 /locks/resource/lock_0000000001
String currentNode = zk.create(
lockPath + "/lock_", // 路径
null, // 数据
EPHEMERAL_SEQUENTIAL // 临时 + 顺序
);
// 2. 获取当前节点下的所有子节点,排序
List<String> children = zk.getChildren(lockPath, false);
Collections.sort(children);
// 3. 判断自己是不是最小的节点
if (currentNode.equals(children.get(0))) {
// 是最小的节点 → 拿到锁 ✅
return true;
} else {
// 不是最小的 → 监听前一个节点(等它释放)
String previousNode = children.get(children.indexOf(currentNode) - 1);
zk.exists(lockPath + "/" + previousNode, watcher);
// 等待前一个节点释放
return false;
}
}
public void unlock() {
// 删除临时节点 → 后一个节点会收到通知,拿到锁
zk.delete(currentNode);
}
}
ZooKeeper 锁的优势:
- 不需要设置过期时间 — 临时节点会随着客户端会话断开自动删除,不会死锁
- 顺序公平 — 先到的人先拿锁,不会有”抢锁”的竞争
- 监听机制 — 释放锁时主动通知下一个等待者,不需要轮询
Redis 锁 vs ZooKeeper 锁
| 特性 | Redis 分布式锁 | ZooKeeper 分布式锁 |
|---|---|---|
| 性能 | 极高(纯内存操作) | 中等(ZAB 协议,写入需过半确认) |
| 可靠性 | 中等(可能丢锁,需要 Redlock 算法) | 高(临时节点自动清理) |
| 死锁 | 靠过期时间防止 | 会话断开自动删除 |
| 公平性 | 非公平(抢锁) | 公平(顺序节点) |
| 实现复杂度 | 简单(SETNX 即可) | 较复杂 |
| 适用场景 | 高并发、对一致性要求不极端的场景 | 对一致性要求高、并发量不太大的场景 |
分布式锁的常见问题
1. 锁的粒度

锁的粒度越细,并发能力越强,但实现越复杂。
❌ 锁整个库存系统:
锁 "lock:stock" → 所有商品扣库存都串行化
✅ 锁单个商品:
锁 "lock:stock:product_10086" → 不同商品互不影响
✅ 锁单个用户的单个商品:
锁 "lock:stock:product_10086:user_999" → 同一个用户的操作串行化
2. 锁的可重入
同一个线程(同一个请求链)多次获取同一把锁,应该允许通过:
// Redisson 的可重入锁
RLock lock = redisson.getLock("lock:stock:10086");
lock.lock(); // 第一次获取锁 ✅
lock.lock(); // 同一个线程再次获取 ✅(可重入)
// 业务逻辑...
lock.unlock();
lock.unlock(); // 释放两次
3. 锁的续期
业务执行时间不可预测,不能依赖固定的过期时间。看门狗机制解决了这个问题——自动续期,直到业务完成。
小结
分布式锁的核心思路是:所有服务器统一去一个中央存储申请锁。
- Redis 锁 — 用
SETNX+ 过期时间,性能高,适合大多数场景 - Redisson 看门狗 — 解决锁自动续期问题,防止锁过期被误删
- ZooKeeper 锁 — 临时顺序节点,公平且不会死锁,适合对一致性要求高的场景
单机锁管线程,分布式锁管服务器。
关注「善忘技术夹」全媒体矩阵
扫描上方宣传海报二维码,第一时间获取最新技术文章、开源项目与免安装小程序体验。