Redis 分布式锁详解( 五 )

当服务宕机时 , 看门狗的线程也就不存在了 , 此时也就不会对锁进行自动续期 , 到了 30s 锁就会自动过期 , 其他线程就可以获取锁了 , 不会造成死锁 。解锁protected RFuture<Boolean> unlockInnerAsync(long threadId) {return evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,"if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then " +// 如果锁不存在"return nil;" +// 解锁失败"end; " +"local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); " +// 否则将锁的重入计数器-1"if (counter > 0) then " +// 如果重入计数器>0"redis.call('pexpire', KEYS[1], ARGV[2]); " +// 将锁续期 30s"return 0; " +// 返回成功"else " +"redis.call('del', KEYS[1]); " +// 否则删除锁"redis.call('publish', KEYS[2], ARGV[1]); " +// 发布解锁消息"return 1; " +// 返回解锁成功"end; " +"return nil;",// 解锁失败Arrays.asList(getName(), getChannelName()), LockPubSub.UNLOCK_MESSAGE, internalLockLeaseTime, getLockName(threadId));}复制代码
流程总结:

  1. 判断锁是否存在 , 如果锁不存在直接返回 null 。
  2. 重入计数器减一(因为支持重入锁的缘故 , 这里不能直接将锁删除) 。
  3. 如果重入计数器还是大于零 , 说明线程还是持有锁的 , 将锁续期 30s , 返回成功 。
  4. 否则删除锁 , 并且发送删除锁的消息(channelName:redisson_lock__channel:{锁 key 值}) , 以通知阻塞队列中的线程尝试加锁 。
  5. 返回解锁成功 。
总结
  • RedissonLock 实现了锁等待(waitTime) , 锁重入 , 锁自动续期等复杂功能 。
  • RedissonLock 实现的分布式锁使用的是 Hash 数据结构 , 其中 Hash key 是我们指定锁的 key 值 ,  filed 是 UUID:threaId , value 是重入锁次数 。其中 UUID 是 Redisson 客户端连接管理器实例初始化生成的 UUID 。使用 Hash 数据结构 , 是实现锁重入的关键 。
  • RedissonLock 加锁 , 解锁 , 看门狗都是用了 Lua 脚本 , 保证命令执行的原子性 。
  • RedissonLock 实现锁等待时间(waitTime)不是使用的 while(true) 手段 , 而是使用的 Redis 发布订阅 , semaphore(信号量)实现的 , 解决了无效锁申请造成的系统资源浪费问题 。
  • 具体实现是使用 semaphore 进行带期限的阻塞线程 , 当锁释放时会发布锁释放的消息 , 收到解锁消息后调用 release() 方法 , 此时被 semaphore 阻塞的等待队列中的一个线程就可以尝试获取锁了 , 如果在指定期限内未获得锁 , 则获取锁失败 。
  • 只有未设置锁超时时间(leaseTime) , 才能使用 Redisson 看门狗机制 。
七、Redis 高可用架构下的分布式锁问题上面讲 Redisson 实现的分布式锁 , 在单机模式下已经趋近完美了 。
但是单点的话故障的话 , 那就芭比 Q 了 , 所以我们第一点想到的是部署高可用集群 。
目前 Redis 高可用架构主要有主从模式 , 哨兵模式 , 集群模式 , 在这三种模式下使用 Redis 分布式锁存在一个弊端 , 可能会导致多个客户端同时加锁成功 。
Redis 分布式锁详解

文章插图
 
客户端 A 加锁成功 , 由于 Reids 主从同步数据是异步执行的 , LockA 锁还没来的及同步到 Slave , 此时 Master 节点宕机了 。
Slave 节点提升为 Master , 客户端 B 来加锁 , 发现没有其他客户端占用锁 , LockB 加锁成功 。
这时就导致了两个客户端同时获取了锁 。
所以 , 如果使用 Redis 分布式锁 , 应尽量避免主从、哨兵或集群模式 。八、红锁(Redlock)1. Redlock 概念RedLock 是 Redis 作者提出的一个算法 。
Redlock 官网介绍
在该算法的分布式版本中 , 我们假设有 N 个 Redis masters 。这些节点是完全独立的 , 所以我们不使用复制或任何其他隐式协调系统 。我们已经描述了如何在单个实例中安全地获取和释放锁 。我们想当然地认为 , 算法将使用这种方法在单个实例中获取和释放锁 。在我们的示例中 , 我们设置了 N=5 , 这是一个合理的值 , 因此我们需要在不同的计算机或虚拟机上运行 5 个 Redis 主机 , 以确保它们以基本独立的方式失败 。


推荐阅读