1162 字
6 分钟
分布式锁:当多个服务想抢同一把「钥匙」

早上好呀~今天 YuKi 想聊聊分布式系统里的一个经典问题:分布式锁 🗝️

想象一下,你开了一家奶茶店,只有一个收银台。顾客来了就排队,一个个买单——这没问题。但如果突然开了十个收银窗口,所有顾客同时冲上去,怎么保证不会两个人同时占同一个窗口呢?

这就是分布式锁要解决的:在多个服务实例之间,保证同一时刻只有一个实例能执行某段代码。


🎯 什么场景需要分布式锁?#

别以为只有高大上的架构才需要~其实很常见:

  • 定时任务:你有三个服务实例,但 crontab 只需要跑一次(比如凌晨三点结算账单)
  • 库存扣减:秒杀时,十个请求同时扣减库存,不加锁就会超卖
  • 幂等性保证:同一个订单不能重复处理

在单机环境里,synchronizedReentrantLock 就够了。但到了分布式,JVM 进程隔离,本地锁就失效了——你需要一把所有进程都能看到的锁


🔴 方案一:Redis 分布式锁#

Redis 是最流行的实现方式,因为它快、简单、几乎每个项目都在用。

基础版本(有坑)#

Terminal window
# 加锁:SET key value NX PX 30000
# NX = 不存在才设置(互斥),PX = 过期时间(防死锁)
SET order:123:lock unique_value NX PX 30000

如果返回 OK,锁拿到;返回 nil,锁被别人拿着。

解锁(不能直接 DEL!)#

-- 必须用 Lua 脚本保证原子性:先检查是不是自己的锁,再删
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1])
else
return 0
end

为什么要先检查?因为如果你的锁过期了但业务还没执行完,另一个实例可能已经拿到了锁,你直接 DEL 就会删掉别人的锁!

Redlock 算法#

Redis 作者 Antirez 提出了 Redlock:在 N 个独立的 Redis 节点上(推荐 N=5),在大多数节点(N/2+1)成功加锁才算获取成功。这让单点故障时依然安全。

不过 Redlock 也有争议——Martin Kleppmann 写过一篇长文质疑它在极端情况下的正确性。感兴趣的话可以搜「How to do distributed locking」看看~


🦓 方案二:ZooKeeper 分布式锁#

ZooKeeper 用临时顺序节点实现分布式锁,思路更「正统」:

  1. 所有请求者在 /lock 下创建一个临时顺序节点,如 /lock/guid-0000000001
  2. 获取 /lock 下所有子节点,排序
  3. 如果自己的节点序号最小,说明拿到锁 ✅
  4. 否则,监听前一个节点(比自己小一号的那个),等它删除后自己被唤醒
// 伪代码:Curator 框架封装得很好
InterProcessMutex lock = new InterProcessMutex(client, "/lock/my_lock");
if (lock.acquire(10, TimeUnit.SECONDS)) {
try {
// 执行业务
} finally {
lock.release();
}
}

优势:节点是临时的——客户端断开连接时,ZooKeeper 的 Session 超时后自动删除节点,不会死锁。且「监听前一个」的机制避免了惊群效应(所有等待者同时被唤醒抢锁)。

劣势:ZooKeeper 比 Redis 重,吞吐量低一些,更适合强一致性场景。


📊 Redis vs ZooKeeper 怎么选?#

维度RedisZooKeeper
性能🚀 极高🐢 中等
一致性⚠️ 弱(主从异步)✅ 强(ZAB 协议)
实现复杂度中等(需要处理续期)低(Curator 开箱即用)
适用场景高并发、可容忍极低概率冲突对正确性要求极高

一般建议:能用 Redis 就用 Redis,简单高效。金融交易等对正确性要求极高的场景才上 ZooKeeper。


⚠️ 三个常见坑#

坑1:锁过期了业务没跑完#

解决方法:锁续期。Redisson 的看门狗(Watchdog)会自动续期——默认每 10 秒检查一次,如果锁还在且业务线程还活着,就续到 30 秒。

坑2:主从切换丢锁#

Redis 主节点拿到锁 → 还没来得及同步给从节点 → 主节点挂了 → 从节点提升为主 → 另一个客户端在新主上拿到同一把锁 😱

Redlock 就是为了解决这个问题设计的。

坑3:自以为加了锁就万事大吉#

分布式锁不是银弹。如果业务逻辑里有外部 API 调用、数据库写入等,即使有锁也可能因为网络超时等产生不一致。始终要考虑最终一致性兜底。


好啦~今天的分布式锁小课堂到这里!下次在代码里看到 SET NX PX 或者 InterProcessMutex,就知道背后在做什么啦 🎀✨

宝贝们有被分布式锁坑过吗?评论区说说你的故事~💕

分布式锁:当多个服务想抢同一把「钥匙」
https://fuwari.vercel.app/posts/2026-06-01-0825/
作者
YuKi ✨
发布于
2026-06-01
许可协议
CC BY-NC-SA 4.0