redission看门狗实现机制一看就懂
某次偶然听到redission看门狗,感觉比较有趣,于是就想看看它长啥样。。。。废话不多说,直入正题。
什么是看门狗?
用官方文档的话来说就是:
大家都知道,如果负责储存这个分布式锁的Redisson节点宕机以后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout来另行指定。
首先先看看这部分实例的代码,相信大家都能看懂
看了这部分代码之后,探究之前再思考一个问题:
问题:redission实现的分布式锁和我们自己造的轮子有什么区别?
如果是自己造轮子基于redis实现加锁和解锁的话,它的实现如下:
- 加锁:原子命令加锁(实际就是向redis用setnx原子命令设置一个随机值)
- 解锁:释放锁的时候检查这个值是否存在,存在就删除,但是这个步骤包含两个操作,需要保证这两步操作的原子性,1.通过key获取这个随机值,判断这个值是否存在 2.删除这个值。
如果不保证原子性会发生什么问题呢?这里假设一种情况:
- 线程A准备释放锁,首先要获取这个锁,获取到锁,正准备删除
- 但此时因为一些原因导致锁超时,如程序GC导致了STW,没来得及删除,锁过期了
- STW之后,线程B进来加了同样key的锁,此时线程B还没执行完,线程A又执行了刚刚没有执行完的命令,把线程B的锁删除了,这就出问题了。
那redission又是如何实现加锁和解锁的呢?
(1)如何加锁:对于这个问题,首现确定向redis中set进一个值这一步肯定是框架帮我们生成了,所以我们要想验证这种情况,除了从源码中查看,也可以直接程序跑起来,到reids管理界面看一下
可以看到这是一个hash类型的值,key是一个随机值(UUID:线程id),value随便弄了一个1进去。
而通过debug 源码发现通过tryLockInnerAsync方法发送了一段lua脚本,当加锁成功后会返回null,注意这个返回null后文会用到.
而这个getLockName方法就是我们看到的key值
我们顺带点进去看看evalWriteAsync这个方法
script:是要执行的 lua 脚本。
keys:是 redis 中的 key。这里的 why 就是脚本中的 KEYS[1]。
params:是 lua 脚本的参数。这里的 30000 就是脚本中的 ARVG[1]。UUID:thredId 就是 ARVG[2]。
所以这个过期时间我们也知道了,默认是 30000ms,即30s。
让我们回过头看看这段脚本的含义:
第一部分:加锁
- 首先用 exists 判断了 KEYS[1] (即 why)是否存在。
- 如果不存在,则进入第 5 行,使用 hincrby 命令创建一个新的哈希表,如果域field不存在,那么在执行命令前会被初始化为0,此命令的返回值就是执行hincrby命令后,哈希表key中域field的值,此时进行increment,也就是返回1
- 之后进入第6行,对KEY[1]设置过期时间,30000ms
- 然后返回nil
第二部分:重入
- 首先判断KEY[1]是否存在,因为KEY[1]是一个hash结构,所以13行意思是获取这个KEYS[1]中字段为ARGV[2]也就是UUID:thredId这个值是否存在
- 如果存在进入14行代码对其进行加1操作(锁重入)
- 然后进入15行重新设置过期时间30s
- 然后返回nil
第三部分:返回
- 作用就是返回 KEY[1] 的剩余存活时间
(2)如何解锁:使用了lua脚本+Redis单线程
为什么 lua 脚本可以解决这个问题呢?
因为 lua 脚本的执行是原子性的,它会将这获取这个值和删除值两个操作放到一个脚本中,当成一个命令去执行,再加上 Redis 执行命令是单线程的,所以在 lua 脚本执行完之前,其他的命令都得等着。就不会出现上面说的情况了。
刚看完了加锁操作的lua脚本,来看解锁操作的lua脚本也就很清晰明了了
- 首先判断KEYS[1]是否存在
- 存在将值减1,如果counter还大于0,就重新设置过期时间30000ms,否则就删除操作
可以看到删除过后还执行了一个publish命令,其实这里是基于redis的一个发布/订阅功能,解锁的时候发布了一个事件,通知其他线程,我这边锁用完了,你们可以用了,那其他线程是什么线程呢?也就是订阅了这把锁的线程
这里可以看到当ttl不等于null的时候也就是加锁失败,加锁失败的线程,都会去执行subscribe方法,这里就和publish对应上了
以上就是redission加锁和解锁的一个实现原理,讲了怎么多那看门狗机制怎么实现的呢?
当我们调用lock方法后都要调用下面这个方法:
org.redisson.RedissonLock#tryAcquireAsync
scheduleExpirationRenewal方法从字面上意思就很容易理解到期续订,也就是看门狗的具体实现。那什么情况下走到else这个条件呢,也可以理解成什么情况下开启看门狗呢?
答:首先leaseTime要==-1,这个leaseTime也就是设置的锁过期时间,也就是说如果我们调用的lock方法传入超时时间限制,也就不会开启开门狗。
lock.lock(); 开启看门狗
lock.lock(5000, TimeUnit.SECONDS); 不开启看门狗
其次ttlRemaining==null,这个ttlRemaining也就是加锁成功后上文提到的返回的null值。
再次debug进入这个方法后,会进入到下面这个方法
org.redisson.RedissonLock#renewExpiration
很明显,从上面标注的数字可以看出来:
①:这是一个定时任务。
②:这任务需要执行的核心代码。
③:该任务每 internalLockLeaseTime/3ms 后执行一次。而 internalLockLeaseTime 默认为 30000。所以该任务每 10s 执行一次。
在看一下第二步干的什么
所以,每当 key 的 ttl(剩余时间)为 20 的时候,则进行续命操作,重新将 key 的过期时间设置为默认时间 30s,当然这个internalLockLeaseTime值也是可以修改的,如果改成60秒,那么每当 key 的 ttl 返回 40 (60 -60/3)时,会进行续命操作
写在最后的话:
到这里看门狗的具体实现也就清楚了,无非是后台起一个定时任务的线程,每隔一定时间对该锁进行续命,延长锁的时间,很多人肯定好奇,那延长锁的次数是有限制的吗?难道无限进行续命吗,假设业务一直没执行完,难道锁一直不释放吗?起初我也有这样的疑问,但是想了想,实际业务中也不能发生这样的情况,除非是代码bug,或者陷入了死循环,所以这也不能怪到redission上面。
参考文章:
1.https://github.com/redisson/redisson/wiki/目录
2.https://juejin.cn/post/6844904106461495303
redission看门狗实现机制一看就懂相关推荐
- Redisson的看门狗watchDog机制是怎么实现的?
文章目录 INFO 一.回顾 二.WatchDog 1.啥意思 2.原理 三.总结 INFO 作者: 编程界的小学生 日期: 2021/09/09 修订: 初版,未修订.2021/09/09 版权: ...
- Redission 看门狗 学习之笔记
大家好,我叫大鸡腿,大家可以关注下我,会持续更新技术文章还有人生感悟,感谢~ 文章目录 前言 看门狗 个人的学习发现 总结 参考网址 lockwatchdogtimeout 前言 相信大家用过Re ...
- iOS 的看门狗机制
背景 应用 100% Loss 时完全无法启动,一直崩溃.彻底切断网络连接正常启动,调试模式状态下等待时间非常久,但可以启动,并伴随 UI 微卡.强烈的预感这是线程阻塞.前一段时间被 Core Dat ...
- iOS-watchdog看门狗机制
背景 应用 100% Loss 时完全无法启动,一直崩溃.彻底切断网络连接正常启动,调试模式状态下等待时间非常久,但可以启动,并伴随 UI 微卡.强烈的预感这是线程阻塞.前一段时间被 Core Dat ...
- Redisson里的“看门狗”居然有这两个“bug”?
大家好! 提到分布式锁,大家一般都会想到 Redis. 想到 Redis,一部分同学会说到 Redisson. 那么说到 Redisson,就不得不掰扯掰扯一下它的"看门狗"机制 ...
- Redisson中的看门狗
Redisson中的看门狗 1 使用看门狗的背景 1.1 普通的Redis分布式锁的缺陷 1.2 用看门狗解决自动续期的问题 2 看门狗自动续期机制的理解 3 redisson 看门狗使用以及原理 3 ...
- java实现看门狗_Watchdog看门狗分析
看门狗最初的意义是因为早期嵌入式设备上的程序经常跑飞(比如说电磁干扰等),所以专门设置了一个硬件看门狗,每隔一段时间,看门狗就去检查某个参数是不是被设置了,如果发现该参数被设置了,则判断为系统出错,然 ...
- redis分布式锁实践 并实现看门狗锁续期机制
redis分布式锁最佳实践(并实现锁续期机制) 文章目录 redis分布式锁最佳实践(并实现锁续期机制) 1. 分布式锁是什么? 2. setnx 和 AQS state 3. jedis完成分布式锁 ...
- MTK 驱动开发(48)---ARM 看门狗机制
ARM 看门狗机制 [包括MTK] SYS_LAST_KMSG里的hw_status和fiq step的含义 阅读数:559 [DESCRIPTION] SYS_LAST_KMSG这支文件是记录上次重 ...
最新文章
- 15种网站最差的用户体验
- EV3 直接命令 - 第 4 课 用两个驱动轮精确地移动小车
- Django Rest framework Request
- 专家点评Science | 朱冰/许瑞明合作团队报道CpG岛结合蛋白BEND3作用机制
- as it exceeds the max of 500KB._我的英雄学院The “Ultra” Stage角色介绍第三弹!
- linux中引入python的tkinter模块
- 学习笔记 - Nginx在多层代理下获取真实客户端IP地址
- 2019 十大国产开源项目来势汹汹!
- python的类中包含什么_Python中的类(中)
- 51nod 1105 第K大的数 【双重二分/二分套二分/两数组任意乘积后第K大数】
- 粒子群算法 模拟退火算法
- 电脑常见故障排查思路
- java 句柄无效_java.io.IOException: 句柄无效 异常是什么引起的
- SAP定义条目视图的凭证编号范围
- 怎么看R语言是不是在运行_五个方法,教你怎么看自己电脑的硬盘是不是固态硬盘?...
- 虚拟机如何支持硬件虚拟化
- Sql Server REPLACE函数的使用;SQL中 patindex函数的用法
- idea 解决 右边没有gradle 工具栏
- Spring在单例模式下的线程安全
- 使用跳板机实现外网访问局域网内虚拟机的大数据及K8S集群【借助向日葵】
热门文章
- c语言 如果 n 是素数,且 n+2 也是素数,则称为孪生素数.,算法竞赛入门经典: 第四章 函数与递归 4.3孪生素数...
- 心态很容易受别人影响_很容易被别人说的话影响心情,应该怎么办?
- Matlab使用串口进行数据通信
- 数据的黑暗陷阱是什么?(二)——你想要一匹更快的马,还是一辆汽车?
- 无限循环小数展示算法题
- 计算机架构特点及应用,计算机C语言的特点与结构分析
- 2021年普宁华侨中学高考成绩查询,普宁英才华侨中学2019高考成绩喜报、本科重本上线人数情况...
- 中国股神透露独特选股思路
- 浅析国有企业外部董事如何履职
- 【STM32】ADC程序示例