好的,我给你整理一下Redis实现分布式锁的七种常见方案,并分析它们的原理、优缺点和适用场景。


Redis 分布式锁 7 种实现方案

1. SETNX + EXPIRE(基本型)

原理

  1. 使用 SETNX key value 尝试获取锁,成功则返回 1。
  2. 再用 EXPIRE key timeout 设置过期时间,防止死锁。

优点

  • 实现简单。

缺点

  • 非原子操作:SETNX 和 EXPIRE 不是原子操作,可能出现死锁。
  • 如果在 SETNX 后还没执行 EXPIRE 就宕机,锁不会释放。

改进

  • 用 Lua 脚本保证原子性(见方案 2)。

2. SETNX + EXPIRE(原子型 / Lua 脚本)

原理

  • 使用 Lua 脚本将 SETNX + EXPIRE 原子化:
if redis.call("setnx",KEYS[1],ARGV[1]) == 1 then
    return redis.call("expire",KEYS[1],ARGV[2])
else
    return 0
end

  • 或使用 Redis 2.6+ 的 SET key value NX PX milliseconds 命令:
SET lock_key unique_value NX PX 3000

优点

  • 原子操作,避免死锁。
  • 支持自动过期。

缺点

  • 仍可能出现锁释放误删,需要 value 唯一标识。

3. 带唯一标识的锁(安全释放)

原理

  • 给锁的 value 设置唯一标识(UUID、线程ID)。
  • 释放锁时,用 Lua 脚本判断 value 是否匹配,防止误删:
if redis.call("get", KEYS[1]) == ARGV[1] then
    return redis.call("del", KEYS[1])
else
    return 0
end

优点

  • 安全释放锁,避免释放别人的锁。

缺点

  • 单机 Redis,如果 Redis 宕机,锁会丢失。

4. Redlock(分布式安全锁)

原理

  • Redis 官方推荐算法。
  • 多个独立 Redis 实例(N=5) 上获取锁。
  • 必须在 大多数节点(>=3) 成功获取锁才能认为锁成功。
  • 设置有效期,超时自动释放。

优点

  • 高可用、安全性高。
  • 避免单机 Redis 宕机导致锁失效。

缺点

  • 算法复杂,实现难度高。
  • 在网络分区情况下仍有争议。

5. 延迟重试 + 自旋锁

原理

  • 获取锁失败时,不立即失败,而是:
    • 自旋重试(忙等)
    • 或 sleep 一段时间后重试

优点

  • 减少锁获取失败带来的业务异常。
  • 简单实现“阻塞式锁”。

缺点

  • 自旋消耗 CPU。
  • 需要合理设置重试间隔和超时时间。

6. 看门狗机制(Redisson实现)

原理

  • Redisson 提供自动续期机制(watchdog)。
  • 锁持有者在锁快到期时自动延长过期时间。

优点

  • 解决业务执行时间长导致锁过期的问题。
  • 使用简单,适合业务不确定耗时场景。

缺点

  • 依赖 Redisson 客户端。
  • 会增加 Redis 额外心跳开销。

7. 公平锁 / 信号量型锁

原理

  • 利用 Redis 列表(List) 实现公平队列:
    • 请求锁时将请求加入队列。
    • 轮到自己时获取锁。
  • 可以扩展为 信号量,允许同时 N 个线程持锁。

优点

  • 避免“饥饿”现象,公平获取锁。
  • 可控制并发量(信号量模式)。

缺点

  • 实现复杂,需要自己维护队列和锁释放逻辑。
  • Redis 内存占用稍大。

总结对比表

方案是否分布式是否安全是否阻塞/等待适用场景
1. SETNX+EXPIRE❌ 单机❌ 可能死锁❌ 非阻塞简单场景
2. SETNX+EXPIRE Lua❌ 单机✅ 原子❌ 非阻塞简单场景,防止死锁
3. 带唯一标识❌ 单机✅ 安全释放❌ 非阻塞单机安全锁
4. Redlock✅ 多机✅ 高安全❌ 可阻塞分布式高可用锁
5. 自旋锁✅ / ❌✅ 阻塞高并发重试
6. 看门狗(Redisson)✅ 多机✅ 自动续期✅ 阻塞长耗时任务
7. 公平锁 / 信号量✅ 多机✅ 阻塞控制并发量,公平获取

如果你需要,我可以帮你画一张Redis分布式锁方案对比图,直观展示 复杂度、分布式特性、安全性,非常适合PPT或技术分享。

你希望我画吗?