★ Redisson 分布式锁原理是什么?主从切换会带来什么问题?
结论先行:Redisson 分布式锁本质是"SET NX + Lua 保证原子性"的封装:key 存锁标识(UUID + 线程号),加锁/续期/解锁都用 Lua 脚本保证原子;未指定租约时会启动看门狗定时续期,防止业务未结束锁先过期。最大的坑是主从架构下主节点加锁后未同步就宕机,从节点升主后锁丢失,另一个客户端可拿到同一把锁,破坏互斥。
一、核心原理
- 加锁:SET key value NX EX,value 为客户端唯一标识,防止误删他人锁;
- 可重入:底层用 hash 结构,field 为线程标识,重复加锁对计数器自增;
- 看门狗:未显式指定租约时默认 30 秒,后台每 10 秒续期,业务没结束锁就不会过期;
- 解锁:Lua 脚本先校验持有者再删除,非持有者调用解锁不生效,整个过程原子;
- 等待机制:拿不到锁的客户端通过发布订阅等待释放通知,而不是盲目轮询;
- 能力扩展:Redisson 还提供公平锁、读写锁与信号量,面试只需点出它们都基于同一套 Lua + 发布订阅机制即可。
二、主从切换下丢锁问题
- 场景:客户端 A 在主节点加锁成功,主节点尚未把数据同步到从节点就宕机,哨兵把从节点提升为主节点,此时锁数据丢失;
- 后果:客户端 B 在新主上加同一把锁成功,A、B 同时持锁,分布式锁互斥性失效,可能产生超卖等严重问题;
- 缓解与讨论:RedLock 要求向多数独立主节点加锁,但存在时钟跳跃、客户端 GC 停顿等争议,业界对其可靠性存疑;
- 更稳妥选择:对强一致敏感的场景改用 ZooKeeper/etcd 的顺序临时节点实现锁,或使用 Redis 的 WAIT 同步尽量缩小窗口,最根本的是用幂等 + 乐观锁兜底,让锁失效不至于造成数据错误;
- 面试延伸:RedLock 争论的核心是"互斥性能否被绝对保证",能说出 GC 停顿与时钟跳跃两个攻击面就算深度答法。
三、使用示例(Java)
RLock lock = redisson.getLock("order:1001");
boolean ok = lock.tryLock(3, 30, TimeUnit.SECONDS); // 等锁 3 秒,租约 30 秒
if (!ok) { return; }
try {
// 业务逻辑
} finally {
if (lock.isHeldByCurrentThread()) { lock.unlock(); }
}
提示:tryLock(waitTime, leaseTime) 显式给租约时看门狗不会续期,业务耗时不可控时应改用不带 leaseTime 的 lock() 让看门狗生效。
常见追问 / 记忆点
- 追问:看门狗有什么用?答:业务执行超过锁默认时间时自动续期,避免锁提前释放导致并发进入临界区。
- 追问:解锁为什么要用 Lua?答:校验持有者与删除必须原子,拆成两步会出现误删其他线程新加的锁。
- 追问:锁过期而业务未完成怎么办?答:尽量缩短临界区、合理设置租约,业务侧用状态校验与幂等兜底。
- 记忆点:SET NX 加锁、Lua 原子释放、看门狗续期,主从异步复制是丢锁根源。