原创

redisson看门狗机制


redisson看门狗机制

先了解下整体流程,如下图

微信截图_20230124222122 这里简单归纳下Redisson分布式锁原理:

  • 可重入:利用hash结构记录线程id和重入次数
  • 可重试:利用信号量和PubSub功能实现等待、唤醒,获取锁失败的重试机制
  • 超时续约:利用watchDog,每隔一段时间 (releaseTime/3),重置超时时间

编写debug测试用例,开始debug

image-20230123172912797

查看tryLock实现

微信截图_20230123173103

点击tryAcquire查看获取锁方法

微信截图_20230123173403

再点击实现方法(这里从名称命名可以看出该方法为异步方法)

微信截图_20230123173519

判断时间是否为负一来确定是否要设置默认值,再点击tryLockInnerAsync获取锁方法实现源码

微信截图_20230123173801

源码内容:在当前的线程域中记录内部锁释放时间,用lua脚本来获取锁。

lua脚本内容:判断锁的key是否不存在,如果不存在就记录锁标识并设置锁重入次数加一,然后设置锁的有效期,返回nil结束;判断锁的key是否是自己的,如果是我自己的锁重入次数加一,然后设置有效期,返回nil结束;如果上述都失败返回失败结果。(pttl获取对应值的剩余有效期,毫秒为单位)

返回上级方法

微信截图_20230123180141

获取完锁后判断返回值是否为空,然后用当最大等待时间减去消耗时间来获取剩余时间,如果等待时间小于获取锁消耗的时间那么返回false;如果还有剩余时间那么再次获取当前时间,在subscribe方法里订阅锁释放信息,再判断(412行)能不能在剩余时间内获取到锁释放信息

微信截图_20230123215125

然后再往下走(425行)获取剩余时间

微信截图_20230123215748

进入无限循环-》尝试获取锁-》 获取剩余时间进行判断-》没过时,判断ttl大于0小于剩余时间用subscribeFuture在ttl的时间内尝试获取锁,反之用subscribeFuture在剩余时间内尝试获取锁-》判断剩余时间是否大于0-》如果大于0继续循环下去

微信截图_20230123221330

锁超时问题(锁续命)

万一业务阻塞ttl到期被其他线程获取到

微信截图_20230123230310

再看回之前的锁获取方法中,当RFuture回调完成后调用onComplete如果ttl为空代表获取锁成功执行到期更新功能(258行)

微信截图_20230123231230

点开执行到期更新方法,程序把所有锁放到一个静态map中以业务名称作为key用putIfAbsent放置进去,这里考虑到锁重入的问题putIfAbsent可以保证获取到的是同一个entry,接着就用renewExpiration去更新有效期

微信截图_20230123232655

可以看到有个定时任务在初始过期时间的三分之一后执行

微信截图_20230123233641

执行的内容:从map中拿出Entry获取线程id刷新有效期(renewExpirationAsync),点开renewExpirationAsync查看

微信截图_20230123233909

lua脚本内容:判断当前的锁是不是这个线程拿的,如果判断成功则尝试更新有效期

微信截图_20230123235239

future执行完成后调用renewExpiration方法,也就是递归(自己调自己)

微信截图_20230123235752

最后把执行后的任务(TimeOut)放到entry里面去

锁释放

查看unlock方法

微信截图_20230124000132

查看unlockAsync方法

微信截图_20230124163555

查看cancelExpirationRenewal(取消到期更新)方法

微信截图_20230124204956

移除map中对应entry的线程,然后把entry里的TimeOut任务给取消掉,最后将map中的entry移除,到此结束。

SpringBoot
Redisson
  • 作者:陌攻(联系作者)
  • 发表时间:2023-03-10 09:54
  • 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
  • 公众号转载:请在文末添加作者公众号二维码
  • 评论