redis分布式锁的续锁方案

本文详细解析了Redisson客户端的分布式锁实现,包括加锁原理、自动续锁机制(看门狗与自定义方案)以及在业务超时后的应对策略。通过实例演示和源码剖析,帮助理解如何避免锁释放导致的问题并确保业务连续性。
摘要由CSDN通过智能技术生成

基于redis的分布式锁,很多人都有用过。今天简单介绍基于redison客户端的分布式锁源码分析,重点内容是关于续锁的问题,具体内容如下。

一、redis分布式锁源码分析

1、redis分布式锁的使用

1)、基于redison客户端创建分布式锁工具,具体代码如下图:
图1

从图1可以看出,这个工具类里面主要的内容是初始化redisson客户端,尝试加锁,释放锁三个操作。

2)、使用RedissonLockUtils对业务代码进行加锁,处理完业务后释放锁,具体代码如下图:
图2

从图2可以看出,释放锁的操作是放在finally块中的,而不是直接放到业务代码后面的。这个是为了防止业务代码异常结束,锁没有释放。

2、redis加锁的源码分析

1)、找到RedissonClient的tryLock方法的具体实现源码,如下图:
  图3

从图3可以看出,tryLock方法中主要的操作是调用tryAcquire去尝试加锁,当加锁未成功后,判断到当前为止,加锁的耗时是否超过加锁等待时间(waitTime),若超过就返回false,表示加锁失败,若没有超过就通过自旋继续加锁,直到加锁成功或超时返回。

2)、看一下tryAcquire方法的源码,如下图:
图4

从图4可以看出,在进行加锁前会判断用户在进行加锁操作的时候是否有传锁的超时时间,如果没有就默认为30秒。然后调用tryAcquireAsync方法进行加锁。

3)、看一下tryAcquireAsync方法的源码,如下图:
图5

从图4可以看出,这里的加锁是通过执行Lua脚本,将给key赋值操作和给key设置超时时间操作合并成一个操作,保证操作的原子性。这样不会出现已经给key赋值了但超时时间没有设置上的问题。

二、续锁方案

上面介绍了如何使用redis分布式锁和分析了加锁的源码。这里我们先来看一个问题:对一个业务代码进行加锁,在执行业务代码的过程中,锁的超时时间到了,锁被释放了,而此时该线程的业务逻辑还没处理完。这个时候如果其他线程获取到了锁,就会导致各种问题。对于这样的问题,就需要在超时时间快到的时候,进行续锁操作(即给锁重新设置超时时间)。续锁方案如下:

1、redission的看门狗(watch dog)自动延期机制。

Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的超时时间。先来看下tryAcquire的源码,如下图:
图6

从图6可以看出,当我们没有设置锁的超时时间的时候,会自动设置超时时间(lockWatchdogTimeout),默认30秒。如下图:
图7

这个自动设置超时时间加锁和我们设置超时时间加锁的区别在于,自动设置超时时间加锁后启动一个看门狗(watch dog),每隔一段时间检查一下,如果业务1还持有锁key,那么就会不断的延长锁key的生存时间。具体的操作是scheduleExpirationRenewal(threadId),源码如下图:
图8

这使用这种方式时需要注意,如果加锁的业务代码一直阻塞会导致这个锁一直被占用,无法释放。

2、自定义的续锁方案。

通常,我们在使用分布式锁的时候,会根据业务的需要,在进行加锁的时候,设置合理的超时时间。但如果设置了锁的超时时间,就不会触发方案一中的看门狗(watch dog)自动延期机制,这个时候就需要自己来设计续锁方案了。在设置续锁方案之前,先看下这个锁在redis中怎样存储的,具体如下图:
图9

其实自定义续锁方案其实和看门狗(watch dog)自动延期机制差不多,就是在加锁的时候,另开一个线程调用续锁的代码。具体代码如下图:
图10

介绍以下这个续锁的代码,它主要的步骤如下:

1)、根据锁key ,获取持有锁的线程在key中的字段和值。

2)、根据自己设置的锁的超时时间,定义一个自旋的时间。

3)、开始自旋再次获取现在redis中锁key中的字段和值。

4)、看再次获取到的字段和值是否存在,不存在就结束续锁操作。若存在就进行下一步。

5)、判断当前的锁key的字段名称和需要续锁key的字段名称是否一样,不一样就可以结束续锁操作。一样就进行下一步。

6)、获取锁的剩余时间,判断剩余时间是否小于等于锁超时时间的1/4。是,就重新设置超时时间,让持有锁的线程继续持有锁。

7)、每隔超时时间的1/4就进行一次续锁判断,看是否需要锁。

测试下上面的续锁的代码,测试代码如下:
图11

运行下,看下redis中key的剩余时间,如下图:
图12

从这个图可以看出,续锁成功了。这个续锁方案可以根据自己需要设置合理的超时时间,在续锁的时候,也可以设置个对续锁操作的超时时间,防止一个持有锁的线程一直阻塞,导致锁一直被占用无法释放。

该文章转载自微信公众号:程序猿分享编程

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值