Redisson分布式锁的源码分析(二)

436 阅读5分钟

前提回顾

在上节中已经分析了分布式锁的Redisson的非公平锁的情况下,是如何通过Lue脚本实现对分布式集群实现锁操作的。

上节链接:juejin.cn/post/702773…

上节遗留问题

如果Redisson进行尝试获取锁后,且成功获取到锁操作。对于没有指定锁的持锁时间,是怎么操作的呢?(或怎么实现锁续命的呢) 在回答上述问题前,必须明确一点,在Redissson在分布式锁实现上(或其他Clustor、ZK实现分布式锁的技术上),都要明确一点就是但服务器发生宕机或意外情况下,保证应用不会出现死锁的情况,必须采用兜底的锁释放策略。 哪策略是啥?

u=1513207404,4035887357&fm=26&fmt=auto.webp

有同学调侃到:叫你不看博主的上节和自定义实现ZK锁策略,且不关注博主 1、ZK采用临时节点,应对其服务器突然宕机导致,锁得不到释放带来死锁情况。
2、Redis采用key的有效时间,指定时间过期后,自动标记为不可读(软删除)。
那没有自定过期时间,且时间已经过了,程序还没执行完,锁被释放了这不会出现问题了吗?有这些疑问那看来,前提工作已经做好了,那回归问题所在?

Redisson是如何实现锁续命的?

这个时候呢,还是得上代码截图,走你

image.png 分析到获取锁成功,我们进入scheduleExpirationRenewal方法看看里面的实现,再来一张代码截图轰炸一波。

啰哩啰嗦的,我自己感觉都废话连篇的

image.png 看到这里会发现,这个里面多了一个ConcurrentMap<String, ExpirationEntry> EXPIRATION_RENEWAL_MAP的集合变量

有同学问?这个是是什么东西?用来干啥子的呢?

分析EXPIRATION_RENEWAL_MAP的构造和内部参数

image.png 可以观察到器内部包含一个线程集合threadIds和timeOut这两个属性
1、threadIds用于记录其线程的重入锁次数。(redisson的锁是可重入的)
2、Timeout其超时任务(即在指定时间内,重新执行操作),其采用netty的TimerTask进行创建的

有同学有疑问了:你在说啥呢 咳咳~~ u=3217786383,3089842583&fm=26&fmt=auto.webp 我的答案是:技术上的东西需要自己去探究,自己去深挖等别人告诉你是不可能的,而且深挖源码,整篇1万字都讲不清楚,只能提示你这是用于干嘛的,指引性作用!详细细节还是得靠自己

如何实现续命的?

上面提到了Timeout这个类,那这个超时任务是怎么实现的,其做了哪些Redis的操作呢(看门狗的实现逻辑)

image.png

对于上述代码详细分析:
1、获取到该锁(anyLock1)的超时节点对象
2、创建一个Timeout指定其超时任务(Timeout对象,其采用netty的TimerTask进行创建的)
3、超时任务中,其采用异步执行redis的Lua脚本(脚本代码renewExpirationAsync(threadId))
4、执行脚本成功完成后,其根据脚本执行结果判断需要递归调用。

超时续命lua脚本分析

renewExpirationAsync(threadId)的内部代码如下图:

image.png

1、判断其anyLock1,中UUID:threadId的fieldId是否存在,如果存在对其进行重新设置超时时间
2、如果不存在直接返回false

聪明好学的同学要提问了:那个没有指定超时时间,那这个internalLockLeaseTime(超时时间)是多少呀?

u=3607208709,3422423430&fm=26&fmt=auto.webp

我也不知道,我们一起跟代码看看吧 我们找到其赋值的节点上的代码: image.png 发现其读取的配置化的看门狗的超时时间。 原来这个值是支持配置化的啊 没错,该值默认时间为30秒。且可以根据用户进行自身配置化修改该时间 那触发续命任务的定时任务的时间是什么时候呢?还是得回代码

image.png 看到这里,可以得出满意的答案了,及默认超时时间的三分之一。
漂亮的答案:对于30秒超时时间,但执行到10秒后,发现锁还没得到释放,超时节点还维护在EXPIRATION_RENEWAL_MAP的集合中,就会触发一次操作reids修改其UUID:threadId的超时时间为30秒。

答案已经找到了,有同学要问了:为啥是1/3超时时间就触发一次呢? 对于这个问题,我也不太清楚该Danila Varatyntsev和Nikita Koksharov的两位大佬的想法。但应该是保证程序在redis的key失效前,让程序有足够的时间重新修改其超时时间吧。有其他同学懂原因的留言告诉我,让我白嫖一波~~~respect~~
想必大家都知道注意点了吧,internalLockLeaseTime时间不能设置太短,如果太短其程序还没完成续命,key已经不在了过期了(人没了) 所以人生得出结论:美好的事情不是不会到来,只是时候未到,唯有命长方可如期而至。 说笑的,所有的美好事情都是都是通过自己拼搏得来的,若想提前成功,若想追上姐姐或追上非同龄人,成为她的依靠,那需要通过付出比同龄人更大的努力,以缩短彼此的差距。
好了,又到总结时间了。

总结

对于redisson的获取锁操作,都是基于redis的lua脚本进行实现的,锁续命也是如此。代码需自己去执行,过程虽枯燥,但还需自己动手跟进啊,事在人为!下期我们分析其解锁的过程吧~~

u=14564042,4251043630&fm=26&fmt=auto.webp
我也向往湛蓝,愿成为你的湛蓝,你知道吗?有一天会成功的~~谢谢