面试时遇到『看门狗』脖子上挂着『时间轮』,我就问你怕不怕? (3)

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 面试时遇到『看门狗』脖子上挂着『时间轮』,我就问你怕不怕? (3)

那么附加题就来了。


附加题:阅读上面材料后,当默认时间被修改为 60s 后,那么每当 key 的 ttl(剩余时间) 返回多少的时候,会进行续命操作?


答:由题可得,时间每过 60s/3 = 20s 时,任务会被触发,看门狗进行工作。


所以,60s -20s =40s。每当 key 的 ttl 返回 40 时,会进行续命操作。


得学会变形,朋友们,明白吗?


接下来,我们看看这个 task 任务是怎么实现的。


可以看到,这个 Timeout 是 netty 包里面的类。


这个 task 任务是基于 netty 的时间轮做的。


面试官追问你:啥是时间轮?


你又不知道。那你接着往下看。


时间轮又是啥?


你听到了时间轮,你首先想到了啥?


听到这个词,就算你完全不知道时间轮,你也该想到,轮子嘛,不就是一个环嘛。

网上随便一搜,你就知道它确实长成了一个环状:


它的工作原理如下:


图片中的时间轮大小为 8 格,每格又指向一个保存着待执行任务的链表。


我们假设它每 1s 转一格,当前位于第 0 格,现在要添加一个 5s 后执行的任务,则0+5=5,在第5格的链表中添加一个任务节点即可,同时标识该节点round=0。


我们假设它每 1s 转一格,当前位于第 0 格,现在要添加一个 17s 后执行的任务,则(0+17)% 8 = 1,则在第 1 格添加一个节点指向任务,并标记round=2,时间轮每经过第 1 格后,对应的链表中的任务的 round 都会减 1 。则当时间轮第 3 次经过第 1 格时,会执行该任务。


需要注意的是时间轮每次只会执行round=0的任务。


知道了工作原理,我们再看看前面说的 Timeout 类,其实就是 HashedWheelTimer 里面 newTimeout 方法的返回:


前面我们分析了,在 Redssion 实现看门狗功能的时候,使用的是 newTimeout 方法。该方法三个入参:


1.task,任务,对于 Redssion 看门狗功能来说,这个 task 就是把对应的 key 的过期时间重置,默认是 30s。


2.delay,每隔多久执行一次,对于 Redssion 看门狗功能来说,这个 delay 就是 internalLockLeaseTime/3 算出来的值,默认是 10s。

3.unit,时间单位。


其实,你发现了吗,这个时候我们已经脱离了 Redssion 进入 Netty 了。


我们只需要告诉 newTimeout 方法,我们要每隔多少时间执行一次什么任务就行。


那我们为什么不自己写个更加简单的,易于理解的 Demo 来分析这个时间轮呢?

比如下面这样的:


上面的 Demo 应该是很好理解了。


到这里,我们知道了看门狗是基于定时任务实现的,而这个定时任务是基于 Netty 的时间轮实现的。


对于 HashedWheelTimer 的源码,开始我还想进行一个导读,写着写着去查阅资料的时候发现,这个链接里面的对于源码的解读已经很到位了,我索性把自己的写那部分删除了,大家有兴趣的可以去阅读一下:


https://www.jianshu.com/p/1eb1b7c67d63

另外,关于时间轮,还可以看一下 IBM 论坛里面的这篇文章《浅析 Linux 中的时间编程和实现原理》:`


https://www.ibm.com/developerworks/cn/linux/1308_liuming_linuxtime3/index.html


解锁操作


还记得我们加锁操作的时候说的吗?


进入,然后加一,你联想到了什么? 
这不就是可重入锁吗! 
看到这里的时候,解锁的 lua 脚本都不必看的,想也能想到,肯定是有一个减一的操作,然后减到 0,就释放这把锁。
一会我们就去验证这个点。


这一小节,我们就去验证这个点,请看下面的释放锁执行的 lua 脚本:


是不是里面有个 counter 的判断,如果减一后小于等于 0。就执行 del key 的操作。


解锁操作确实挺简单,主要是 del 之后执行了一个 publish 命令。你猜这里 publish 的是啥?


先猜再验证嘛,大胆假设,小心求证!


这里是基于 redis 的发布/订阅功能。解锁的时候发布了一个事件,你觉得通知的是什么玩意?


肯定是告诉别的线程,我这边锁用完了,你来获取吧。


别的线程是什么线程呢?


就是想要申请同一把锁的线程。


tryAcquire 的代码我们之前分析过,当 ttl 不为 null 时,只有一种情况,那就是加锁失败:


所以加锁失败的线程就执行了 subscribe 方法,完成了订阅。

这样,就和释放锁时的 publish 操作呼应上了。


接下来就只剩下一个问题没有解决了:怎么让看门狗知道不用续命了?


其实就是在执行完解锁的 lua 脚本之后,通过响应式编程,完成了 cancel 操作。


自此,我们的加锁、看门狗续命、解锁的一套操作就完成了。


补充说明,顺便打脸


在打脸之前,我先问个问题吧:看门狗什么情况下会失效?


别给我说宕机,宕机之后,由于线程没了,看门狗只是不续命了, redis 里面的 key 到期之后就删除了。


我问的失效是指什么时候完全就不启动?


答案是,调用 lock 方法的时候传进一个指定时间,这样如果指定时间之内没有调用 unLock 方法,该锁还是会被释放的。就像下面这样:


rLock.lock(5,TimeUnit.SECONDS);

该锁在 5s 之后就会自动释放了。不会进行续命操作!!!


对应的源码如下,注意看我写的注释:


所以,我想起很久之前我在群里说的这个,红框框起来的部分是错的:


明确指定了超时时间的时候,是不会启动看门狗机制。


自己打自己脸的事......


好爽啊,这事我经常干。


而且,读书人的事,这能叫打脸吗?这叫成长。


另外,这图画的挺好的,分享给大家:


图片来源:https://juejin.im/post/5bf3f15851882526a643e207

还有一个读者提出的问题,续租的时候,是否需要进行次数的限制?


我觉得是不需要限制的,如果你的代码一直在进行续期操作,说明两种情况:


1.由于某种异常原因,导致你本次需要处理的数据比之前的多,所以,需要的时间更长,导致一直在进行续期操作。


2.你的代码有问题,导致了死循环,也就是死锁的出现,这个锅,Redssion 不背。


最后,还有一个问题,这锁安全吗,或者说你觉得会有什么问题?


什么?你不知道?

之前分享过的文章中说过了:


节点之间异步通信,会出现上面描述的情况。所以 Redis 推出的解决方案是啥?


RedLock,之前写的《求锤得锤之神仙打架》这篇文章,就是讲 RedLock 的。如果你不知道,你就去瞅一眼。


其实后来有一天我突然想到, 如果从 CAP 的角度上去看 Redis 分布式锁问题,我觉得可能更好理解一点。


分布式锁的一致性要求 CP,但是Redis 集群架构之间的异步通信满足的是 AP ,因此对不上呀,就是有问题的啊。


但是为什么 Redis 做分布式锁还是那么流行呢?


可能是因为大多场景中可以容忍它的这个问题,也可能是使用者存在侥幸心理吧,或者说使用者就当个黑盒使用,根本不知道可能会出问题。


最后说一句(求关注)


写完之后一看时间又是凌晨 2 点过了:


点个“在看”吧,周更很累的,不要白嫖我,需要一点正反馈。


才疏学浅,难免会有纰漏,如果你发现了错误的地方,还请你留言给我指出来,我对其加以修改。(我每篇技术文章都有这句话,我是认真的说的。)


感谢您的阅读,我坚持原创,十分欢迎并感谢您的关注。


我是why技术,一个不是大佬,但是喜欢分享,又暖又有料的四川好男人。


欢迎关注公众号【why技术】,坚持输出原创。分享技术、品味生活,愿你我共同进步。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
4月前
|
搜索推荐 Windows
让你的电脑准时“打个盹”:Win10定时休眠
木头左教你设置Windows 10任务计划程序,让电脑定时休眠,节约能源又呵护健康。首先确保休眠功能开启,然后在任务计划程序创建新任务,命名如“定时休眠”,设置触发时间和操作(cmd.exe /c shutdown -h)。可高级定制,如条件触发或异常处理。跟着步骤实践,解决常见问题,打造个性化自动休眠计划。记得谨慎操作哦!
|
算法 Cloud Native
【刷题日记】2039. 网络空闲的时刻
本次刷题日记的第 9 篇,力扣题为:2039. 网络空闲的时刻 ,中等
太难了!面试官居然要我停止一个正在运行的线程?
停止一个线程意味着在任务处理完任务之前停掉正在做的操作,也就是放弃当前的操作。停止一个线程可以用Thread.stop()方法,但最好不要用它。虽然它确实可以停止一个正在运行的线程,但是这个方法是不安全的,而且是已被废弃的方法。
|
存储 NoSQL
3.10.0-693.5.2内核nfs客户端租约过期挂死问题分析
## 现象 1. 边缘存储两个节点fileserver,glance挂载物理机上的挂载点均出现挂住无法访问 2. 从客户端抓包看,客户端内核间隔5s向服务端发送renew租约请求,服务端返回NFS4ERR_EXPIRED,即租约过期错误,从抓包现象看客户端一直向服务端发送相同的clientid renew请求,服务端一直返回租约过期错误,导致挂载点无法恢复 ![](https://ata2-img
1614 1
3.10.0-693.5.2内核nfs客户端租约过期挂死问题分析
|
监控 网络协议 Dubbo
开工第一天,这个超时问题把我干趴下了!
开工第一天,这个超时问题把我干趴下了!
|
NoSQL 安全 Java
面试时遇到『看门狗』脖子上挂着『时间轮』,我就问你怕不怕? (1)
面试时遇到『看门狗』脖子上挂着『时间轮』,我就问你怕不怕? (1)
132 0
|
算法 NoSQL 程序员
面试时遇到『看门狗』脖子上挂着『时间轮』,我就问你怕不怕? (2)
面试时遇到『看门狗』脖子上挂着『时间轮』,我就问你怕不怕? (2)
190 0
|
程序员
空闲时间请大家不要接私活,要提升自己!
  现在社会,有很多人都在利用个人时间兼职赚钱,程序员俗称“接私活”,其他行业称作兼职,比如下了班出去跑滴滴,周末兼职抢单送外卖等等,都是普通人很常见的兼职方式。   甚至很多技术同行,我听说也有周末去跑滴滴和送外卖的,我觉得很不可思议,然而我的观点是如果你想成为成功人士,高收入人群那么你不应该去做兼职,不要把你宝贵的时间,浪费在兼职上。   简单经济学分析   涉及到收入,文字洗脑显得很空洞了就,那么今天我给你来一个简单的经济学论调。   我们看一个案例,李嘉诚是香港首富,但是李嘉诚会亲自修剪自家的草坪吗?除非某一天他想体验一下劳动乐趣什么的,否则一定是请人来修剪草坪。
145 0
|
Web App开发 SQL Java
艾伟_转载:一次挂死(hang)的处理过程及经验
前言:        CPU占用率低,内存还有许多空余,但网站无法响应,这就是网站挂死,通常也叫做hang。这种情况对于我这样既是CEO,又是CTO,还兼职扫地洗碗的个人站长来说根本就是家常便饭。以下是一次处理hang的经验及总结,前后用了一个月,不仅涉及程序排查,数据库优化,还有硬件升级的苦恼。
1641 0
|
Web App开发 SQL Java
艾伟:一次挂死(hang)的处理过程及经验
前言:        CPU占用率低,内存还有许多空余,但网站无法响应,这就是网站挂死,通常也叫做hang。这种情况对于我这样既是CEO,又是CTO,还兼职扫地洗碗的个人站长来说根本就是家常便饭。以下是一次处理hang的经验及总结,前后用了一个月,不仅涉及程序排查,数据库优化,还有硬件升级的苦恼。
1673 0