📢 欢迎来到万事技术论坛!本站仅讨论合法编程技术话题,严禁外挂/作弊/黑产/盗版内容,违者封号。

精华分布式锁的三种实现与各自的坑

lin_dev 活跃会员

单机 synchronized 跨进程就失效了,得上分布式锁。三种常见做法:

一、Redis SETNX

SET lock:order:123 <uuid> NX PX 30000

NX 保证只有一个客户端能设上,PX 给过期时间防死锁,value 用 <uuid> 是为了只能解自己加的锁。

释放时必须用 Lua 保证原子性(先比对 uuid 再删):

if redis.call('get', KEYS[1]) == ARGV[1] then
  return redis.call('del', KEYS[1])
else
  return 0
end

坑:业务执行时间超过锁过期时间,锁被别人拿走,两个线程同时进入临界区。解法是「看门狗」自动续期(Redisson 的 watchdog),或者把过期时间设得足够大 + 业务侧幂等兜底。

二、数据库唯一索引 / 悲观锁

INSERT INTO locks (name, owner) VALUES ('order:123', 'uuid');
COMMIT;

依赖唯一约束,抢到插入成功即拿到锁。

坑:锁释放(删行)后连接异常没删干净会永久死锁,必须配合超时清理任务。性能也最差,高并发下别用。

三、ZooKeeper / etcd 临时顺序节点

客户端建临时节点,会话断开节点自动消失,天然防死锁;顺序节点实现公平锁。

坑:性能不如 Redis,且有「GC 停顿导致会话超时」的经典问题——JVM 长时间 STW,ZK 以为客户端挂了删了锁,等 GC 结束客户端以为自己还持有锁。etcd 的 lease 机制同理。

怎么选

方案 性能 可靠性 适用
Redis 高 中(有超期风险) 大多数业务,允许偶发失效
数据库 低 中 已有 DB、并发低
ZK / etcd 中 高 金融、强一致场景

我的建议:绝大多数场景 Redis + 看门狗 + 业务幂等 就够了,别为了「绝对可靠」上 ZK,运维成本翻倍。

楼主 · 2026-09-28 13:21 · 浏览 3
ops_wang 进阶会员

GC 停顿那个坑我们线上真遇到过,ZK 会话超时把锁放开了,两个节点同时跑定时任务,数据写了两份。后来改成数据库唯一约束兜底才好。

1楼 · 2026-09-28 13:21
登录 后即可参与回复。