Redis实现分布式锁有哪些方案?

请讲解下,Redis实现分布式锁有哪些方案?
最新回答
迷失了就不酷了

2026-10-19 14:25:51

Redis实现分布式锁有以下六种方案:

方案一:SETNX + EXPIRE
  • 原理:使用SETNX命令尝试获取锁,若成功(返回1),则使用EXPIRE命令为锁设置过期时间,防止死锁。
  • 缺陷:加锁与设置过期时间是非原子操作,若加锁后未设置过期时间系统就异常,会导致锁无法释放。
  • 示例:SETNX key_resource_id valueEXPIRE key_resource_id 30
方案二:SETNX + value值(系统时间 + 过期时间)
  • 原理:将过期时间嵌入SETNX的value中,加锁时无需单独调用EXPIRE。解锁时检查当前时间与value中的过期时间,判断锁是否有效。
  • 优点:避免了单独设置过期时间的非原子性问题。
  • 缺陷:

    依赖客户端时间同步,若时间不同步可能导致锁提前或延迟释放。

    锁无持有者标识,可能被其他客户端误释放。

  • 示例:value = System.currentTimeMillis() + expireTimeSETNX key_resource_id value
方案三:使用Lua脚本(包含SETNX + EXPIRE两条指令)
  • 原理:通过Lua脚本将SETNX和EXPIRE合并为原子操作,确保加锁和设置过期时间同时成功或失败。
  • 优点:原子性保证,避免竞争条件。
  • 示例:-- 加锁脚本if redis.call("SETNX", KEYS[1], ARGV[1]) == 1 then redis.call("EXPIRE", KEYS[1], ARGV[2]) return 1else return 0endEVAL "脚本内容" 1 key_resource_id value 30
方案四:SET的扩展命令(SET EX PX NX)
  • 原理:利用Redis的SET命令扩展参数(NX、EX/PX),实现原子化的加锁和过期时间设置。
  • 参数说明:

    NX:仅当键不存在时设置。

    EX seconds:设置秒级过期时间。

    PX milliseconds:设置毫秒级过期时间。

  • 优点:简洁高效,原子性由Redis内部保证。
  • 示例:SET key_resource_id value EX 30 NX
方案五:开源框架Redisson
  • 原理:Redisson通过Watchdog机制解决锁过期但业务未完成的问题。加锁成功后启动后台线程,定期检查锁状态并延长过期时间。
  • 优点:

    自动续期,避免业务未完成时锁被释放。

    提供可重入锁、公平锁等高级特性。

  • 示例:RLock lock = redisson.getLock("key_resource_id");lock.lock(); // 默认30秒过期,Watchdog自动续期
方案六:多机实现的分布式锁Redlock(Redisson支持)
  • 原理:基于多个Redis节点(独立部署)实现分布式锁,通过多数节点同意确保锁的可靠性。步骤如下:

    客户端向所有节点请求加锁。

    若超过半数节点返回成功,则认为加锁成功。

    锁的过期时间需扣除网络延迟和时钟漂移。

  • 优点:适用于集群环境,避免单点故障。
  • 示例(Redisson配置):Config config = new Config();config.useClusterServers() .addNodeAddress("redis://node1:6379") .addNodeAddress("redis://node2:6379");RedissonClient redisson = Redisson.create(config);RLock lock = redisson.getLock("key_resource_id");lock.lock();
总结
  • 单机环境:优先选择方案四(SET EX PX NX)或方案五(Redisson),兼顾原子性和易用性。
  • 集群环境:使用方案六(Redlock)确保高可用性。
  • 避免方案一和方案二:因存在非原子性或时间同步问题,仅适用于简单场景。