好的,我来给你整理一份Redis 实现分布式锁的 7 种方案,详细分析原理、优缺点以及适用场景,便于开发者选择。


Redis 实现分布式锁的 7 种方案


方案 1:SETNX + 过期时间

原理

  • 使用 Redis 的 SETNX(SET if Not eXists)命令保证原子性,设置 key 仅在不存在时成功
  • 搭配 EXPIRE 设置过期时间,防止死锁
String lockKey = "lock";
String lockValue = UUID.randomUUID().toString();
Long acquired = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, 10, TimeUnit.SECONDS);
if (acquired != null && acquired) {
    // 获取锁成功
}

优点

  • 简单易实现
  • 原子性通过 SETNX 保证

缺点

  • 释放锁需小心,避免误删别人锁(需校验 value)
  • 如果业务时间大于过期时间,锁会自动释放导致安全问题

方案 2:SET NX PX

原理

  • Redis 2.6.12+ 支持原子操作 SET key value NX PX ttl,一次命令即可设置锁和过期时间
SET lockKey lockValue NX PX 10000

优点

  • 原子性操作,一步完成锁和过期时间
  • 安全性比方案 1 高

缺点

  • 依然有业务执行时间超过锁时间的风险

方案 3:带过期时间的 value + Lua 脚本释放锁

原理

  • value 保存唯一标识(UUID)
  • 使用 Lua 脚本判断 value 是否是自己,再删除锁,保证释放原子性
if redis.call("get", KEYS[1]) == ARGV[1] then
    return redis.call("del", KEYS[1])
else
    return 0
end

优点

  • 解决误删别人的锁问题
  • 原子性释放

缺点

  • 仍可能出现锁超时问题

方案 4:Redisson 实现分布式锁

原理

  • Redisson 是 Java Redis 客户端,封装了分布式锁实现
  • 支持可重入锁、公平锁、读写锁等
RLock lock = redisson.getLock("lock");
lock.lock(10, TimeUnit.SECONDS);
// 业务执行
lock.unlock();

优点

  • 简单易用,功能完善
  • 自动续期机制防止锁过期

缺点

  • 依赖第三方库,增加项目依赖

方案 5:RedLock 算法(多节点 Redis)

原理

  • 由 Redis 作者提出
  • 在 N 个 Redis 实例上分别尝试获取锁,必须在大多数节点获取成功才算成功
  • 防止单点故障,提高可靠性

优点

  • 高可用,防止单节点 Redis 宕机导致锁失效
  • 避免 split-brain 问题

缺点

  • 实现复杂
  • 对网络延迟敏感

方案 6:使用 Redis 发布/订阅 + 队列(阻塞锁)

原理

  • 当锁被占用时,将请求放入等待队列
  • 释放锁时,发布消息通知下一个客户端获取锁

优点

  • 可以实现阻塞等待
  • 避免大量客户端空循环获取锁

缺点

  • 需要额外维护队列和 pub/sub 消息
  • 延迟较高

方案 7:利用 Redis 的 SETBIT/INCR 实现分布式锁

原理

  • 将锁状态保存在位图或计数器
  • 原子性操作如 SETBIT 或 INCR 判断是否已被占用
  • 常用于高性能场景

优点

  • 高性能,占用内存小
  • 适合高并发场景

缺点

  • 实现复杂,容易出错
  • 可读性差,不直观

总结与建议

方案安全性易用性适用场景
SETNX + EXPIRE简单锁需求
SET NX PX推荐小型项目
Lua 脚本释放锁需要保证释放安全
RedissonJava 项目推荐
RedLock高可用分布式环境
队列 + Pub/Sub阻塞等待场景
SETBIT/INCR超高并发、高性能场景

✅ 推荐实践:

  • 单机 Redis → 使用 SET NX PX + Lua 脚本
  • 多节点 Redis → 使用 Redisson + RedLock