面试问题

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

问题分析

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

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

如何回答

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

Redisson分布式锁的底层原理

redisson实现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实例宕机的时候,可能导致多个客户端同时完成加锁。

redis watchdog_干货:Redis分布式锁的原理以及如何续期相关推荐

  1. Redis分布式锁的原理以及如何续期

    面试问题 Redis锁的过期时间小于业务的执行时间该如何续期? 问题分析 首先如果你之前用Redis的分布式锁的姿势正确,并且看过相应的官方文档的话,这个问题So easy.我们来看 很多同学在用分布 ...

  2. Redis进阶- Redisson分布式锁实现原理及源码解析

    文章目录 Pre 用法 Redisson分布式锁实现原理 Redisson分布式锁源码分析 redisson.getLock(lockKey) 的逻辑 redissonLock.lock()的逻辑 r ...

  3. redis实现分布式锁的原理

    redis实现分布式锁的原理 一.为什么使用分布式锁? ·>本地锁的局限性: ·>分布式锁的概念: 二.redis实现分布式锁的原理? 1.抢占分布式锁: 2.加锁的同时设置过期时间: 3 ...

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

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

  5. Redis 分布式锁实现原理

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

  6. Day137-139.尚品汇:制作SKU、商品详情、项目优化:Redis缓存、redssion分布式锁

    目录 Day5  制作SKU 1. 制作SKU 2. 多表查询如何写? 3. 制作SKU 4. Thymeleaf Day06 商品详情 1. 获取分类信息 2. 获取最新价格信息 3. 获取销售信息 ...

  7. redisson redlock(基于redisson框架和redis集群使用分布式锁)

    一.关于分布式锁的两篇文章 文章1 文章2 二.redis分布式锁存在的问题 redis实现分布式锁有很多种方案,比较完善的方案应该是用setNx + lua进行实现.简单实现如下: java代码-加 ...

  8. Redis与Zookeeper实现分布式锁的区别

    Redis与Zookeeper实现分布式锁的区别 1.分布式锁解决方案 1.采用数据库 不建议 性能不好 jdbc 2.基于Redis实现分布式锁(setnx)setnx也可以存入key,如果存入ke ...

  9. 在 Redis 上实现的分布式锁

    由于近排很忙,忙各种事情,还有工作上的项目,已经超过一个月没写博客了,确实有点惭愧啊,没能每天或者至少每周坚持写一篇博客.这一个月里面接触到很多新知识,同时也遇到很多技术上的难点,在这我将对每一个有用 ...

  10. redis set 超时_redis分布式锁3种实现方式对比分析总结

    我在这篇文章提到了分布式锁,但没有展开来讲,抛砖引玉,今天就来说说高并发服务编程中的redis分布式锁. 这里罗列出3种redis实现的分布式锁,并分别对比说明各自特点. Redis单实例分布式锁 实 ...

最新文章

  1. nginx: [error] invalid PID number in /usr/local/webserver/nginx/logs/nginx.pid
  2. linux查看端口访问用户,如何查找连接到HTTP或HTTPS端口的所有客户端
  3. 个人计算机与手机的区别,手机与电脑的CPU是一回事吗?一共有六大区别,看看你知道多少!...
  4. 2020年前端面试之JS手写代码题合集
  5. linux 将任务挂到后台,linux下使用screen或则nohup将任务放到后台运行
  6. “大胃王”吃播注意了 国家明确禁止发布量大多吃、暴饮暴食等节目
  7. linux命令行模式下实现代理上网 专题
  8. 【手把手带你入门深度学习之150行代码的汉字识别系统】学习笔记 ·001 用OpenCV制作数据集
  9. 移动**21*设置无法接通_手机通话质量不好?你可能只差一步设置!
  10. sublime 自定义快捷生成代码块
  11. 初学 PS 手绘入门小技巧整理【持续更新】
  12. Modelica运算符
  13. 云和大数据,铺就宁夏特色“信息高速路”
  14. 大数据背景下的智慧物流:物流行业解决方案
  15. C++ 读取 HDF5
  16. 中职计算机数据库教学总结,中职计算机专业的数据库课程教学
  17. 基于MATLAB图像处理
  18. 谷歌浏览器中文乱码问题
  19. Android中身份证正反面、营业执照横竖版的拍摄和裁剪
  20. LR(0)项目集规范族的构造及LR(0)分析表的构造

热门文章

  1. 多元Huffman编码问题
  2. vue 中watch函数名_vue中watch的使用
  3. 3809. 修改数组——AcWing题库
  4. 统计某个字符串出现的次数
  5. php oauth单点登陆,php单点登录
  6. labview创建case结构_操作者框架(AF)系列视频学习笔记之视频三:创建简易操作者...
  7. 日历小程序C语言,微信小程序实现日历功能
  8. powerpc如何移植Linux系统,PowerPC平台 u-boot 移栽
  9. 耳挂式蓝牙耳机原理_专为运动而生的DOSS T63无线蓝牙耳挂式运动耳机
  10. 消息中间件—RocketMQ的RPC通信(一)