某次偶然听到redission看门狗,感觉比较有趣,于是就想看看它长啥样。。。。废话不多说,直入正题。

什么是看门狗?
用官方文档的话来说就是:

大家都知道,如果负责储存这个分布式锁的Redisson节点宕机以后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout来另行指定。

首先先看看这部分实例的代码,相信大家都能看懂

看了这部分代码之后,探究之前再思考一个问题:

问题:redission实现的分布式锁和我们自己造的轮子有什么区别?

如果是自己造轮子基于redis实现加锁和解锁的话,它的实现如下:

  • 加锁:原子命令加锁(实际就是向redis用setnx原子命令设置一个随机值)
  • 解锁:释放锁的时候检查这个值是否存在,存在就删除,但是这个步骤包含两个操作,需要保证这两步操作的原子性,1.通过key获取这个随机值,判断这个值是否存在 2.删除这个值。

如果不保证原子性会发生什么问题呢?这里假设一种情况:

  1. 线程A准备释放锁,首先要获取这个锁,获取到锁,正准备删除
  2. 但此时因为一些原因导致锁超时,如程序GC导致了STW,没来得及删除,锁过期了
  3. 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看门狗实现机制一看就懂相关推荐

  1. Redisson的看门狗watchDog机制是怎么实现的?

    文章目录 INFO 一.回顾 二.WatchDog 1.啥意思 2.原理 三.总结 INFO 作者: 编程界的小学生 日期: 2021/09/09 修订: 初版,未修订.2021/09/09 版权: ...

  2. Redission 看门狗 学习之笔记

    大家好,我叫大鸡腿,大家可以关注下我,会持续更新技术文章还有人生感悟,感谢~ 文章目录 前言 看门狗 个人的学习发现 总结 参考网址 lockwatchdogtimeout 前言   相信大家用过Re ...

  3. iOS 的看门狗机制

    背景 应用 100% Loss 时完全无法启动,一直崩溃.彻底切断网络连接正常启动,调试模式状态下等待时间非常久,但可以启动,并伴随 UI 微卡.强烈的预感这是线程阻塞.前一段时间被 Core Dat ...

  4. iOS-watchdog看门狗机制

    背景 应用 100% Loss 时完全无法启动,一直崩溃.彻底切断网络连接正常启动,调试模式状态下等待时间非常久,但可以启动,并伴随 UI 微卡.强烈的预感这是线程阻塞.前一段时间被 Core Dat ...

  5. Redisson里的“看门狗”居然有这两个“bug”?

    ​大家好! 提到分布式锁,大家一般都会想到 Redis. 想到 Redis,一部分同学会说到 Redisson. 那么说到 Redisson,就不得不掰扯掰扯一下它的"看门狗"机制 ...

  6. Redisson中的看门狗

    Redisson中的看门狗 1 使用看门狗的背景 1.1 普通的Redis分布式锁的缺陷 1.2 用看门狗解决自动续期的问题 2 看门狗自动续期机制的理解 3 redisson 看门狗使用以及原理 3 ...

  7. java实现看门狗_Watchdog看门狗分析

    看门狗最初的意义是因为早期嵌入式设备上的程序经常跑飞(比如说电磁干扰等),所以专门设置了一个硬件看门狗,每隔一段时间,看门狗就去检查某个参数是不是被设置了,如果发现该参数被设置了,则判断为系统出错,然 ...

  8. redis分布式锁实践 并实现看门狗锁续期机制

    redis分布式锁最佳实践(并实现锁续期机制) 文章目录 redis分布式锁最佳实践(并实现锁续期机制) 1. 分布式锁是什么? 2. setnx 和 AQS state 3. jedis完成分布式锁 ...

  9. MTK 驱动开发(48)---ARM 看门狗机制

    ARM 看门狗机制 [包括MTK] SYS_LAST_KMSG里的hw_status和fiq step的含义 阅读数:559 [DESCRIPTION] SYS_LAST_KMSG这支文件是记录上次重 ...

最新文章

  1. 15种网站最差的用户体验
  2. EV3 直接命令 - 第 4 课 用两个驱动轮精确地移动小车
  3. Django Rest framework Request
  4. 专家点评Science | 朱冰/许瑞明合作团队报道CpG岛结合蛋白BEND3作用机制
  5. as it exceeds the max of 500KB._我的英雄学院The “Ultra” Stage角色介绍第三弹!
  6. linux中引入python的tkinter模块
  7. 学习笔记 - Nginx在多层代理下获取真实客户端IP地址
  8. 2019 十大国产开源项目来势汹汹!
  9. python的类中包含什么_Python中的类(中)
  10. 51nod 1105 第K大的数 【双重二分/二分套二分/两数组任意乘积后第K大数】
  11. 粒子群算法 模拟退火算法
  12. 电脑常见故障排查思路
  13. java 句柄无效_java.io.IOException: 句柄无效 异常是什么引起的
  14. SAP定义条目视图的凭证编号范围
  15. 怎么看R语言是不是在运行_五个方法,教你怎么看自己电脑的硬盘是不是固态硬盘?...
  16. 虚拟机如何支持硬件虚拟化
  17. Sql Server REPLACE函数的使用;SQL中 patindex函数的用法
  18. idea 解决 右边没有gradle 工具栏
  19. Spring在单例模式下的线程安全
  20. 使用跳板机实现外网访问局域网内虚拟机的大数据及K8S集群【借助向日葵】

热门文章

  1. c语言 如果 n 是素数,且 n+2 也是素数,则称为孪生素数.,算法竞赛入门经典: 第四章 函数与递归 4.3孪生素数...
  2. 心态很容易受别人影响_很容易被别人说的话影响心情,应该怎么办?
  3. Matlab使用串口进行数据通信
  4. 数据的黑暗陷阱是什么?(二)——你想要一匹更快的马,还是一辆汽车?
  5. 无限循环小数展示算法题
  6. 计算机架构特点及应用,计算机C语言的特点与结构分析
  7. 2021年普宁华侨中学高考成绩查询,普宁英才华侨中学2019高考成绩喜报、本科重本上线人数情况...
  8. 中国股神透露独特选股思路
  9. 浅析国有企业外部董事如何履职
  10. 【STM32】ADC程序示例