好的,阿杰,我帮你整理一份 Redis 实现分布式锁的完整指南,包括 7 种常见方案、原理分析、优缺点,以及 正确使用姿势。这对于高并发系统或者分布式应用非常关键。


Redis 分布式锁指南

1️⃣ 分布式锁概念

  • 分布式锁:用于在分布式环境中保证同一资源的 互斥访问
  • 核心要求
    1. 互斥性:同一时刻只有一个客户端能持有锁
    2. 可重入性(可选):同一客户端可以重复获取
    3. 超时释放:防止死锁
    4. 可靠性:锁状态不会丢失
  • Redis 优势
    • 单线程保证操作原子性
    • 支持过期时间,避免死锁
    • 可通过 SET key value NX PX expire 实现

2️⃣ 7 种 Redis 分布式锁实现方案

方案 1:SETNX + EXPIRE

SETNX lock_key 1
EXPIRE lock_key 10

  • 原理
    • 使用 SETNX(key 不存在才设置)加锁
    • 使用 EXPIRE 设置超时时间
  • 缺陷
    • 非原子操作:在 SETNX 和 EXPIRE 之间宕机会导致死锁
  • 不推荐

方案 2:SETNX + Lua 脚本删除

  • 思路
    • 给锁加唯一标识(UUID)
    • 释放锁前检查是否是自己持有
if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

  • 优点:防止误删其他客户端锁
  • 缺点:依然需要手动处理过期时间

方案 3:SET key value NX PX expire(一条命令)

SET lock_key UUID NX PX 10000

  • 解释
    • NX:key 不存在才设置
    • PX:过期时间(毫秒)
  • 优点
    • 原子性操作,解决方案 1 的死锁问题
  • 缺点
    • 锁超时可能导致业务执行未完成就释放锁

方案 4:Redisson Java 客户端

  • 特性
    • 高级客户端,封装了分布式锁实现
    • 支持可重入锁、看门狗机制自动延长过期时间
RLock lock = redisson.getLock("myLock");
lock.lock(10, TimeUnit.SECONDS);
try {
    // 业务逻辑
} finally {
    lock.unlock();
}

  • 优点
    • 简单、安全、可重入
    • 支持自动续期

方案 5:Redlock(多 Redis 实例)

  • 原理
    1. 同时在 N 个 Redis 节点尝试加锁
    2. 只要获得多数节点锁,则认为加锁成功
    3. 超时释放防止死锁
  • 优点:适用于分布式高可靠环境
  • 缺点:复杂,需要多节点部署
  • 参考Redlock 官方算法

方案 6:队列 + Lua 脚本(公平锁)

  • 思路
    • 用 List 保存请求队列
    • Lua 脚本保证原子性
    • 按顺序加锁,保证公平性
  • 适用场景
    • 对请求顺序敏感的业务

方案 7:Pub/Sub + 锁释放通知

  • 原理
    • 客户端获取锁失败时,订阅释放通知
    • 锁释放后立即尝试获取
  • 优点
    • 避免频繁轮询 Redis(减少 CPU 消耗)
  • 缺点
    • Pub/Sub 可靠性不如轮询或 Redlock

3️⃣ 正确使用 Redis 分布式锁的姿势

  1. 加锁使用唯一标识
    • 每个客户端持有不同 UUID,释放时检查防止误删
  2. 设置合理超时时间
    • 锁超时 > 业务执行时间
    • Redisson 可使用 看门狗机制自动续期
  3. 业务执行放在 try-finally
    • 避免异常导致锁未释放
  4. 高可用场景选择 Redlock 或 Redisson
    • 单节点 Redis 在宕机时可能导致锁不可靠
  5. 避免死锁
    • 使用超时机制
    • 不在锁内调用耗时操作或阻塞操作

4️⃣ 总结对比

方案原子性可重入自动续期适用场景
SETNX+EXPIRE简单单节点,不推荐
SETNX+Lua单节点安全加锁
SET NX PX单节点,简单安全
RedissonJava 分布式系统首选
Redlock✅(多数节点)高可靠分布式系统
Lua队列锁公平锁场景
Pub/Sub通知避免轮询、节省资源

💡 核心结论

  • Java 开发 → 推荐 Redisson
  • 高可用、多节点 → 推荐 Redlock
  • 单节点、简单业务 → 使用 SET key value NX PX expire 即可
  • 必须防止误删 → 加 UUID + Lua 脚本