Redis分布式锁Redisson剖析

一、什么是Redisson

1.Redisson是架设在Redis基础上的一个Java驻内存数据网格(In-Memory Data Grid),它实现了分布式和可扩展的Java数据结构。

2.它不仅提供了一系列的分布式的Java常用对象,还实现了可重入锁(Reentrant Lock)、公平锁(Fair Lock)、联锁(MultiLock)、红锁(RedLock)、 读写锁(ReadWriteLock)等,还提供了许多分布式服务。

二、Redisson的宗旨

促进使用者对redis的关注分离,从而让使用者能够将精力更集中地放在处理业务逻辑上。

三、分布式锁的实现

Redis要实现分布式锁,必须满足以下条件

  • 互斥性:在任意时刻,只有一个客户端能持有锁。
  • 无死锁:客户端在持有锁期间,如果出现宕机,不能释放锁,导致后续其他客户端无法获取锁,必须保证宕机情况下,也能释放锁。
  • 容错性:只要大部分的redis节点正常运行,客户端就可以加解锁。

1、分布锁的演变
以前实现分布式锁是基于jedis+Lua脚本,但jedis是线程不安全的,常常通过JedisPool连接池去管理实例,在多线程情况下让每个线程有自己独立的jedis实例,但是随着现代系统的多核和异步,为了不断提高的吞吐量,异步非阻塞线程模型大行其道,Redisson底层是从用Netty框架,出身既是贵族,很多大厂都开始用Redisson实现分布式锁。

2、采用Resisson实现分布式锁

  • 配置文件pom.xml

在这里插入图片描述

  • application.yaml

在这里插入图片描述

  • 配置类config(只做单点连接)

在这里插入图片描述

  • 实现类

在这里插入图片描述

  • 步骤1:源码分析

在这里插入图片描述

  • 步骤2:源码分析

RedissonLock实现Rlock接口,重写tryLock方法

在这里插入图片描述
沿着tryLockAsync()往下走,到最底层是Lua脚本

在这里插入图片描述
eval命令执行Lua代码完成加锁操作。KEYS[1]为锁在redis中的key,key对应value为map结构,ARGV[1]为锁超时时间,ARGV[2]为锁value中的key。ARGV[2]由UUID+threadId组成,用来标记锁被谁持有。
流程:
1、第一个if判断key是否存在,如果不存在,就获取锁,赋值,设置过期时间。
2、第二个if判断key是否存在,如果存在,对比ARGV[2]判断请求的标记值和锁的标记值是否一样,如果一样,则说明已经获取了锁,这时候hincrby锁重入+1,(redis.call(‘hincrby’, KEYS[1], ARGV[2], 1);记录同一线程持有锁之后累计加锁次数实现锁重入)。
3、重置锁的过期时间 。
4、加锁失败,返回锁的过期时间。
----------------------------------------------------------xx--------------------------------------------------------

对于获取不到的锁的线程,它会继续请求获取锁,直接到锁被释放

在这里插入图片描述
A
表示以共享方式获取锁,获取不到进入重复阻塞,如果阻塞时间超过连接时间,解除阻塞,线程中断,抛出异常InterruptedException。

  • 步骤3:解锁

在这里插入图片描述
流程
第一个if判断KEYS[1]是否存在,ARGV[3]的标记是否相同(防止释放错锁),不存在返回nil。
第二个if判断KEYS[1]的可重入次数是否大于0,说明此key还要继续利用,不能释放,大于0重新设置过期时间,小于0的话,则释放KEY[1],并重新设置锁,通知阻塞线程获取锁。
-------------------------------------------------------xx-----------------------------------------------------------
执行release操作,调用acquire,被阻塞的线程继续获取锁。(查了资料,看了别的博主,此处还是弄不太懂,望老司机指点下)

在这里插入图片描述
问题:如果获取锁的线程,锁的过期时间小于线程执行任务的时间,会导致线程还未执行完,锁就面临过期,被释放掉,其他线程获取锁,修改数据,造成数据的值对应不上

Watch dog:自动延期机制
一般锁的默认释放时间为30秒,线程获取锁的同时,后台会自动运行一个watch dog线程,来监视此锁,每隔10秒检查一下,如果此线程还拥有此锁,那么就延长10秒。

四、分布式锁存在的风险

如果存储key的那个节点挂了的话,就可能存在丢失锁的风险,导致出现多个客户端持有锁的情况:
1、客户端A从master获取锁。
2、在master将锁同步到slave之前,master宕机了(因为主从复制是异步的,所以宕机的时候,master有锁,slave无锁),然后主从切换,slave节点被晋级为master节点。
3、客户端B此时请求获取锁,发现原slave节点里没有锁,因此会创建锁并获取,此时会跟客户端A取到同一个锁,导致同一时刻不止一个线程获取到锁。

五、附图

在这里插入图片描述
在这里插入图片描述

六、结语

如果有不足或不对之处,劳烦各位看官帮忙指出,万分感谢!爱你们(笔芯)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值