1. 基于 Redis 实现分布式锁的正确姿势?

为什么需要分布式锁:多实例部署时 JVM 锁(synchronized)只锁本机,无法互斥跨实例的并发操作(如扣库存)。

完整要点(每个都是坑):

  1. 加锁要原子:SET key value NX EX 30 —— NX(不存在才设)+ EX(过期时间)一条命令,不能拆成 SETNX + EXPIRE 两步(中间崩溃锁永不释放)
  2. value 要唯一:UUID/线程 ID,用于释放时校验"是我的锁"
  3. 释放要 Lua 原子校验删除:GET 比对 value 一致才 DEL——不能先 GET 再 DEL(两步间锁可能已被他人重新获取,误删别人的锁)
  4. 过期时间:锁持有时间要设上限,防止持锁方崩溃后死锁
标准实现(Lua 保证原子性)
// 加锁(一条命令原子完成)
SET lock:order:100 uuid NX EX 30

// 释放(Lua 脚本:值匹配才删除,原子)
if redis.call("get", KEYS[1]) == ARGV[1] then
    return redis.call("del", KEYS[1])
else
    return 0
end

🎯 面试要点

  • 三个"必须":加锁必须一条 SET NX EX、value 必须唯一、释放必须 Lua 校验
  • 获取锁失败要重试(带退避),别空转;获取要设超时,别无限等
  • 锁粒度:锁资源 ID(lock:order:100)而不是全局一把锁(锁粒度小并发高)

2. Redisson 的看门狗机制解决什么问题?

问题:业务执行时间 > 锁过期时间 → 锁提前释放 → 其他线程拿到锁 → 两个线程同时执行临界区。

看门狗(Watchdog):Redisson 加锁后启动后台定时任务,每 10 秒(锁 TTL 的 1/3)自动续期到 30 秒。只要持锁线程还活着,锁就不会过期;线程挂了,看门狗随线程终止,锁按 TTL 自动释放。自动续期 = 防死锁 + 防提前释放两全。

另外 Redisson 还支持:可重入(RLock)、公平锁、读写锁、红锁(RedissonMultiLock)。

RLock 标准用法
RLock lock = redisson.getLock("lock:order:100");
boolean locked = false;
try {
    locked = lock.tryLock(3, 30, TimeUnit.SECONDS);  // 等待 3s,锁 30s,看门狗续期
    if (!locked) throw new RuntimeException("获取锁失败");
    // 业务...
} finally {
    if (locked) lock.unlock();   // 自动执行 Lua 校验删除
}

🎯 面试要点

  • 看门狗的本质:定时续期 + 进程死亡自动释放(Redis 键过期机制兜底)
  • 手动指定 leaseTime(锁时长)时看门狗不生效(不用续期)
  • 面试延伸:锁续期失败(Redis 抖动)怎么办 → 业务做幂等兜底(数据库唯一约束)

3. 红锁(RedLock)?分布式锁的选型对比?

RedLock(红锁):单主节点锁的隐患是——主节点加锁成功但未同步到从节点就宕机 → 从节点升主 → 锁丢了,两个线程同时持锁。RedLock 思路:向 N/2+1 个独立节点依次加锁,多数成功才算持锁,多数加锁失败则回滚释放。代价:部署复杂、性能下降。

分布式锁选型对比:

方案 可靠性 性能 适用
Redis SETNX中(主从切换可能丢锁)高大多数业务场景
ZooKeeper高(临时节点+ZAB 顺序)中(会话心跳)强一致性场景
ETCD高(Raft + lease)中高云原生/分布式配置

工程判断:Redis 锁(+幂等兜底)满足 99% 业务;对锁丢失零容忍(资金类)选 ZK/ETCD 或数据库唯一约束。不要为了理论完美把系统做复杂。

🎯 面试要点

  • 经典追问"RedLock 是否真的安全"(作者 Martin Kleppmann 与 Antirez 论战):时钟跳跃、GC pause 都会让锁失效——知道这个争论是加分项
  • 终极兜底:锁 + 幂等(唯一索引/状态机)双保险才是生产常态
  • DB 实现锁:SELECT FOR UPDATE 或唯一索引插入,简单但性能差、有单点

🎤 常见面试追问

  1. 分布式锁的三个"必须"?——加锁必须一条命令 SET key value NX EX(不能拆 SETNX+EXPIRE);value 必须唯一(UUID,防误删);释放必须 Lua 校验值一致才删(防删别人的锁)。
  2. 看门狗(Watchdog)解决什么问题?——业务执行时间 > 锁 TTL 时锁提前释放导致并发。看门狗每 10 秒自动续期到 30 秒,线程活着锁不过期,线程死了锁按 TTL 释放。
  3. Redis 锁和 ZooKeeper 锁怎么选?——Redis:性能高、实现简单,但主从切换可能丢锁;ZK:临时节点 + 顺序节点,强一致但慢。资金级强一致选 ZK/ETCD,一般业务 Redis + 幂等兜底。
  4. RedLock 是什么?争议在哪?——向多个独立节点加锁、多数成功才算持锁,防"主节点加锁后没同步就宕机"的丢锁。争议:时钟跳跃/GC pause 仍可能让锁失效(Martin 与 Antirez 论战)。
  5. 锁失效的终极兜底是什么?——幂等设计(数据库唯一约束/状态机):锁只是"减少冲突",业务本身要能容忍重复执行——双保险才是生产常态。

📖 名词解释(本页术语)

术语 大白话解释
分布式锁多台机器互斥访问共享资源的锁(JVM 锁只管本机)。典型实现:Redis SETNX / ZK 临时节点。
SETNXSET if Not eXists:键不存在才设置——分布式锁的核心命令(配 EX 过期时间)。
Lua 脚本Redis 支持原子执行的小脚本——"判断值再删除"必须用 Lua 保证原子,否则两步之间会被插队。
看门狗(Watchdog)Redisson 的自动续期机制:锁快过期时自动续期,防"业务没跑完锁先没了"。
RLockRedisson 提供的锁接口(可重入、可超时、带看门狗),生产直接用。
RedLock(红锁)多节点多数派加锁方案,解决单节点丢锁问题,但复杂且有争议。
幂等同一操作重复执行结果一致。分布式锁的终极兜底(唯一索引/状态机)。
⚠️ 本页面由 AI 生成,内容仅供参考,请以官方文档和实际源码为准。