面试问题

Redis锁的过期时间小于业务的执行时间该如何续期?

问题分析

首先如果你之前用Redis的分布式锁的姿势正确,并且看过相应的官方文档的话,这个问题So easy.我们来看

很多同学在用分布式锁时,都是直接百度搜索找一个Redis分布式锁工具类就直接用了,其实Redis分布式锁比较正确的姿势是采用redisson这个客户端工具

如何回答

只要客户端一旦加锁成功,就会启动一个watch dog看门狗,他是一个后台线程,会每隔10秒检查一下,如果客户端还持有锁key,那么就会不断的延长锁key的生存时间。

默认情况下,加锁的时间是30秒,.如果加锁的业务没有执行完,就会进行一次续期,把锁重置成30秒.那这个时候可能又有同学问了,那业务的机器万一宕机了呢?宕机了定时任务跑不了,就续不了期,那自然30秒之后锁就解开了呗.

底层原理

redisson实现Redis分布式锁的底层原理

拜托,面试请不要再问我Redis分布式锁的实现原理【石杉的架构笔记】

1)加锁机制

咱们来看上面那张图,现在某个客户端要加锁。如果该客户端面对的是一个redis cluster集群,他首先会根据hash节点选择一台机器。

这里注意,仅仅只是选择一台机器!这点很关键!

紧接着,就会发送一段lua脚本到redis上,那段lua脚本如下所示:

为啥要用lua脚本呢?

因为一大坨复杂的业务逻辑,可以通过封装在lua脚本中发送给redis,保证这段复杂业务逻辑执行的原子性

那么,这段lua脚本是什么意思呢?

KEYS[1]代表的是你加锁的那个key,比如说:

RLock lock = redisson.getLock("myLock");

这里你自己设置了加锁的那个锁key就是“myLock”。

ARGV[1]代表的就是锁key的默认生存时间,默认30秒。

ARGV[2]代表的是加锁的客户端的ID,类似于下面这样:

8743c9c0-0795-4907-87fd-6c719a6b4586:1

给大家解释一下,第一段if判断语句,就是用“exists myLock”命令判断一下,如果你要加锁的那个锁key不存在的话,你就进行加锁。

如何加锁呢?很简单,用下面的命令:

hset myLock

8743c9c0-0795-4907-87fd-6c719a6b4586:1 1

通过这个命令设置一个hash数据结构,这行命令执行后,会出现一个类似下面的数据结构:

上述就代表“8743c9c0-0795-4907-87fd-6c719a6b4586:1”这个客户端对“myLock”这个锁key完成了加锁。

接着会执行“pexpire myLock 30000”命令,设置myLock这个锁key的生存时间是30秒。

好了,到此为止,ok,加锁完成了。

(2)锁互斥机制

那么在这个时候,如果客户端2来尝试加锁,执行了同样的一段lua脚本,会咋样呢?

很简单,第一个if判断会执行“exists myLock”,发现myLock这个锁key已经存在了。

接着第二个if判断,判断一下,myLock锁key的hash数据结构中,是否包含客户端2的ID,但是明显不是的,因为那里包含的是客户端1的ID。

所以,客户端2会获取到pttl myLock返回的一个数字,这个数字代表了myLock这个锁key的剩余生存时间。比如还剩15000毫秒的生存时间。

此时客户端2会进入一个while循环,不停的尝试加锁。

(3)watch dog自动延期机制

客户端1加锁的锁key默认生存时间才30秒,如果超过了30秒,客户端1还想一直持有这把锁,怎么办呢?

简单!只要客户端1一旦加锁成功,就会启动一个watch dog看门狗,他是一个后台线程,会每隔10秒检查一下,如果客户端1还持有锁key,那么就会不断的延长锁key的生存时间。

(4)可重入加锁机制

那如果客户端1都已经持有了这把锁了,结果可重入的加锁会怎么样呢?

比如下面这种代码:

这时我们来分析一下上面那段lua脚本。

第一个if判断肯定不成立,“exists myLock”会显示锁key已经存在了。

第二个if判断会成立,因为myLock的hash数据结构中包含的那个ID,就是客户端1的那个ID,也就是“8743c9c0-0795-4907-87fd-6c719a6b4586:1”

此时就会执行可重入加锁的逻辑,他会用:

incrby myLock

8743c9c0-0795-4907-87fd-6c71a6b4586:1 1

通过这个命令,对客户端1的加锁次数,累加1。

此时myLock数据结构变为下面这样:

大家看到了吧,那个myLock的hash数据结构中的那个客户端ID,就对应着加锁的次数

(5)释放锁机制

如果执行lock.unlock(),就可以释放分布式锁,此时的业务逻辑也是非常简单的。

其实说白了,就是每次都对myLock数据结构中的那个加锁次数减1。

如果发现加锁次数是0了,说明这个客户端已经不再持有锁了,此时就会用:

“del myLock”命令,从redis里删除这个key。

然后呢,另外的客户端2就可以尝试完成加锁了。

这就是所谓的分布式锁的开源Redisson框架的实现机制。

一般我们在生产系统中,可以用Redisson框架提供的这个类库来基于redis进行分布式锁的加锁与释放锁。

(6)Redis分布式锁的缺点

其实上面那种方案最大的问题,就是如果你对某个redis master实例,写入了myLock这种锁key的value,此时会异步复制给对应的master slave实例。

但是这个过程中一旦发生redis master宕机,主备切换,redis slave变为了redis master。

接着就会导致,客户端2来尝试加锁的时候,在新的redis master上完成了加锁,而客户端1也以为自己成功加了锁。

此时就会导致多个客户端对一个分布式锁完成了加锁。

这时系统在业务语义上一定会出现问题,导致各种脏数据的产生

所以这个就是redis cluster,或者是redis master-slave架构的主从异步复制导致的redis分布式锁的最大缺陷:在redis master实例宕机的时候,可能导致多个客户端同时完成加锁。

(7)Redis红锁

Redis作者针对Redis分布式锁的缺点提出了红锁的概念算法如下:

  1. 顺序向五个节点请求加锁
  2. 根据一定的超时时间来推断是不是跳过该节点
  3. 三个节点加锁成功并且花费时间小于锁的有效期
  4. 认定加锁成功

也就是说,假设锁30秒过期,三个节点加锁花了31秒,自然是加锁失败了。这只是举个例子,实际上并不应该等每个节点那么长时间,就像官网所说的那样,假设有效期是10,那么单个redis实例操作超时时间,应该在5到50毫秒(注意时间单位)还是假设我们设置有效期是30秒,图中超时了两个redis节点。那么加锁成功的节点总共花费了3秒,所以锁的实际有效期是小于27秒的。即扣除加锁成功三个实例的3秒,还要扣除等待超时redis实例的总共时间。

关于红锁的争论:Martin Kleppmann和antirez的redLock辩论. 一个是很有资历的分布式架构师,一个是redis之父。
所以说如果项目里要使用红锁,除了红锁的介绍,不妨要多看两篇文章,即:

  1. Martin Kleppmann的质疑贴
  2. antirez的反击贴

有些人是不是觉得大佬们都是杠精啊,天天就想着极端情况。 其实高可用嘛,拼的就是99.999...% 中小数点后面的位数。

其实,在实际场景中,红锁是很少使用的。这是因为使用了红锁后会影响高并发环境下的性能,使得程序的体验更差。所以,在实际场景中,我们一般都是要保证Redis集群的可靠性。同时,使用红锁后,当加锁成功的RLock个数不超过总数的一半时,会返回加锁失败,即使在业务层面任务加锁成功了,但是红锁也会返回加锁失败的结果。另外,使用红锁时,需要提供多套Redis的主从部署架构,同时,这多套Redis主从架构中的Master节点必须都是独立的,相互之间没有任何数据交互。

参考文章

拜托,面试请不要再问我Redis分布式锁的实现原理【石杉的架构笔记】

每秒上千订单场景下的分布式锁高并发优化实践!【石杉的架构笔记】

红锁的实现 - IT路上的小白 - 博客园

细说Redis分布式锁 - 知乎

Redis分布式锁的原理以及如何续期相关推荐

  1. redis分布式锁实现原理_redis分布式锁实现分析与实践

    前言: 在分布式环境中, 我们有些情况下需要使用到锁进行并发控制, 可供基于的 redis, zookeeper,mysql类数据库 基于数据库类的实现是乐观锁, 基于redis,zookeeper的 ...

  2. 面试必需要明白的 Redis 分布式锁实现原理!

    点击蓝色"架构文摘"关注我哟 加个"星标",每天上午 09:25,干货推送! 作者 | Vt 来源 | juejin.im/post/5e61a454e51d4 ...

  3. Redis 分布式锁实现原理

    官方叫做RedLock算法,是redis官方支持的分布式锁算法. 这个分布式锁有3个重要的考量点,互斥(只能有一个客户端获取锁),不能死锁,容错(大部分redis节点或者这个锁就可以加可以释放) 第一 ...

  4. Redis分布式锁实现原理

    一.使用 1.pom.xml导入依赖 <dependency><groupId>org.springframework.boot</groupId><arti ...

  5. Redis分布式锁的原理、作用及实现(简单易懂)

    转载地址:https://blog.csdn.net/d1562901685/article/details/54881862: setnx+getset方式  加锁:setnx(lock, 时间戳+ ...

  6. 17、Redis、Zk分布式锁实现原理

    我们在编程有很多场景使用本地锁和分布式锁,但是是否考虑这些锁的原理是什么?本篇讨论下实现分布式锁的常见办法及他们实现原理. 一.使用锁的原则 使用本地锁和分布式锁是为了解决并发导致脏数据的场景,使用锁 ...

  7. 电商项目实战之缓存与Redis分布式锁

    电商项目实战之缓存与Redis分布式锁 缓存失效 缓存穿透 缓存雪崩 缓存击穿 分布式缓存 分布式锁 SpringBoot整合Redisson实现分布式锁 实现过程 缓存和数据库一致性 场景分析 解决 ...

  8. 分布式锁 哨兵模式_手撕redis分布式锁,隔壁张小帅都看懂了!

    前言 上一篇老猫和小伙伴们分享了为什么要使用分布式锁以及分布式锁的实现思路原理,目前我们主要采用第三方的组件作为分布式锁的工具.上一篇运用了Mysql中的select -for update实现了分布 ...

  9. Redis分布式锁如何提高可用性

    在编程中我们时常考虑高并发带来的数据访问不安全问题,那么我们在redis中是否也要考虑呢?答案是肯定的,有人会问:redis不是单线程的吗?对它是单线程,但是在某些情况他会出现信息更新,用户没有拿到最 ...

最新文章

  1. “5G 消息”APP 短暂上线,它会干掉微信还是变成另一个飞信?
  2. Kubectl get pods 一直处于 Status:containerCreating
  3. 解决SSH登录无响应timed out问题
  4. 左右滑动实现activity之间的跳转
  5. 【java】Thread.Sleep 与 Thread.onSpinWait
  6. python包裹和运费_这个Python库真的太好用了,10行代码就能轻松搞定目标检测
  7. 20210427:力扣第238周周赛(下)
  8. InstallShield 12 制作安装包
  9. 学籍专业填计算机还是理工,学生程序论文,关于高职非计算机专业理工类《C语言程序设计》课程的教学相关参考文献资料-免费论文范文...
  10. 百胜erp加密狗驱动_百胜分销系统ERP_DRP用户手册.pdf
  11. php高级视频教程下载_50个G的PHP视频教程全集下载
  12. CV笔记5:图像分割之最大类间方差法、自适应阈值分割(基于python-opencv实现)
  13. 惠普打印机如何取消任务
  14. 博客怎么推广才能达到最佳优化效果
  15. am解调matlab程序,AM调制解调的matlab仿真
  16. quartz提示This scheduler instance is still active but was recovered by another instance in the cluster
  17. http://www.jb51.net/softjc/33896.html(vs2010破解)
  18. 历数PC发展史上的祖先们
  19. 探究vite——新一代前端开发与构建工具(一)
  20. Nest中央空调控制器 舒适节能两手抓

热门文章

  1. 任务八 触发器的创建和使用
  2. Kibana自动刷新设置
  3. CREO:CREO软件之草绘【草绘】之设置、获取数据、操作、基准、草绘、编辑、约束、尺寸、检查、构造模式的使用方法之详细攻略
  4. aac音乐下载分享-张学友-情歌岁月精选
  5. 加息点阵图与贵金属白银走势
  6. 基于QGraphicsView、QGraphicsScene、自定义QGraphicsItem的小demo(正矩形、旋转矩形及圆形)
  7. 北大青鸟BENET课程---ENBM知识点总结
  8. 2019年程序员岗位招聘信息分析
  9. ESI.ProCAST.2019详细安装指南
  10. android 播放视频结束回调,Android万能音频播放器09-添加Seek功能和完成播放回调...