面试官:都说用 Redis 做分布式锁,那如果 Redis 宕机了,锁不就丢了吗?
你的“标准答案”可能隐藏着致命漏洞,如何破局?
刚开始面试后端岗位的时候,经常遇到这样一个经典问题:“你们项目里的分布式锁是怎么做的?”
大部分人的第一反应是:这题我熟!用 Redis 的 SETNX 加过期时间,再配合 Lua 脚本保证释放锁的原子性,完美!
当你洋洋洒洒在白板上写下这段自认为无懈可击的代码,以为稳操胜券时,资深面试官往往会微微一笑,抛出一个致命追问:
“你这方案在单机上确实没问题,但如果在生产环境中,Redis 主节点刚加锁成功就宕机了,主从切换导致锁丢了,两个服务同时拿到了同一把锁,怎么办?”
很多人在这个问题上瞬间卡壳。这其实不是在刁难你,而是在考察你对高并发架构下**极端情况(Corner Case)**的把控能力,以及对 CAP 定理的真实理解。
如果你弄懂了主从复制背后的原理,你会发现这其实是一个关于**可用性(AP)和一致性(CP)**的艰难抉择。
🪤 看似完美的“标准答案”
大部分人的回答(单机版):
// 最常见的加锁姿势:尝试获取锁,设置过期时间防止死锁
success, err := redisClient.SetNX(ctx, "order_lock:123", "unique_client_id", 10*time.Second).Result()
if success {
// 抢到锁了,赶紧去扣库存...
// 执行完毕,释放锁
redisClient.Del(ctx, "order_lock:123")
}
为了防止别人误删你的锁,还会配合 Lua 脚本来保证“释放锁”的原子性(只删除属于自己的锁):
-- Lua 脚本:我是这把锁的主人,我才能删它
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
这种方案在单机 Redis 下运行非常丝滑,但在高可用集群架构中,它却像一颗定时炸弹。
💥 灾难是如何发生的?(主从切换的背刺)
为什么锁会丢?
在真实的生产环境中,为了防止单点故障,Redis 都是采用 主从架构(Master-Slave) 部署的。
而 Redis 的主从数据同步,是异步的!这就给极端情况留下了致命的缝隙。
灾难场景模拟:
- 👤 客户端 A 向 主节点(Master) 申请锁,成功抢到了
order_lock:123。 - ⚠️ 致命瞬间:主节点还没来得及把这把锁的记录同步给从节点(Slave),突然断电宕机了!
- 🔄 哨兵(Sentinel)系统火速救场,把原来的从节点提拔为新的主节点。
- 🤷♂️ 此时,新主节点上根本没有刚才那把锁的记录。
- 👤 客户端 B 跑来申请同一把锁,新主节点一看,没人在用,直接放行:加锁成功!
- 💣 Boom! 客户端 A 和 B 同时拿到了同一把分布式锁,一起去扣减库存,导致严重的超卖事故。
这就像老板(Master)刚在一份独家授权书上签了字,还没来得及告诉秘书(Slave),老板就晕倒了。秘书临时接班成新老板,因为不知道上一份授权已经签过,转手又把独家授权签给了另一家公司。天下大乱!
🛡️ 破局之道:两种截然不同的架构思想
遇到这种无解的局面,业界有两套经典的解法,代表了两种截然不同的架构哲学。
方案一:Redlock(红锁)算法 —— 试图在 AP 架构里找平衡
Redis 的作者 antirez 也知道这个问题,于是他提出了 Redlock 算法。
核心思想是:别搞什么主从了,直接搞几个完全独立的 Redis 节点(比如 5 个)。
红锁的工作流程:
+ 1. 客户端获取当前时间戳。
+ 2. 轮流向 5 个独立的 Redis 节点请求加锁。
+ 3. 只有当大多数节点(N/2 + 1,即 3 个)都加锁成功,并且总耗时没超过锁的有效期。
+ 4. 才算真正拿到了锁!如果失败,就全部解锁。
这就好比一份合同必须找 5 个合伙人签字,只要拿到 3 个人的签名才算生效。即使倒下了一两个,也不影响大局。
方案二:拥抱 Zookeeper / etcd —— 极致的强一致性(CP)
如果你的业务是金融交易,错一分钱都要命,那千万别用 Redis 做锁了,直接上 Zookeeper 或 etcd。
Zookeeper 采用的是 CP 模型(一致性优先)。它在加锁时,必须等大多数节点都同步完数据,才会告诉你“加锁成功”。
Zookeeper 的降维打击优势:
+ 强一致性:就算主节点挂了,新选出来的主节点也绝对有之前加锁的记录,死死咬住不丢锁。
+ 临时顺序节点:客户端断开连接,节点自动消失,天然防死锁。
+ Watch 机制:没抢到锁就阻塞等着,别人释放了主动通知你,不用像 Redis 那样傻乎乎地一直轮询(自旋)。
🎯 选择的黄金法则(面试标准话术)
那面试时到底该怎么选?千万别说“哪个好用哪个”,要根据业务场景来定!
什么时候用 Redis(主从/集群)?
// 绝大部分互联网高并发场景(电商秒杀、防重复提交)
// 性能极高,虽然极端情况下有千万分之一的概率丢锁,但可以通过定时对账或数据库唯一索引兜底。
const redisLock = new RedisLock();
什么时候用 Zookeeper / etcd?
// 金融转账、财务结算、库存绝对不允许出错的核心链路
// 宁可性能差一点(慢几十毫秒),也绝对不能允许两个人同时拿到锁。
const zkLock = new ZKLock();
什么时候用 Redlock(红锁)?
// 实际生产中并不推荐(争议很大)
// 部署成本高,且严重依赖服务器时钟,如果发生时钟跳跃(Clock Jump),依然会丢锁。
// 业界大佬 Martin Kleppmann 曾专门发文喷过 Redlock,认为它既不快也不安全。
✅ 总结:为什么面试官爱问这个问题?
当面试官抛出“Redis 宕机导致锁丢失”这个问题时,他其实并不是非要你手写一个红锁算法,他想看的是:
- 你是否清楚底层组件的局限性(主从异步复制的坑)。
- 你是否具备架构思维(在可用性 AP 与一致性 CP 之间做权衡)。
- 你是否有兜底意识(知道锁可能会丢,业务上设计了补偿机制)。
分布式架构中没有完美的银弹,只有最适合当前业务的取舍。理解了“锁为什么会丢”,你才真正从一个“调包侠”迈进了高级开发的门槛,这就是技术深度的价值。
写在最后:
最近私信问我面试题的小伙伴实在太多了,一个个回有点回不过来。
我花了两个周末,把星球里大家公认最容易挂的 Go/Java/AI 面试坑点 整理成了一份 PDF 文档。里面不光有题,还有解题思路和避坑指南。
想要的同学,直接关注并私信我 【面试】,我统一发给大家。
wangzhongyang.com 也欢迎大家直接访问我的官网,里面有Go / Java / AI 的资料,免费学习!
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)