基于Redisson实现分布式锁

Redisson场景介绍

首先在了解一个陌生的技术的时候,首先在你的脑海中有这么几个问题?
它是来干嘛的?
哦,你发现它是用来解决高并发下线程不安全的问题的。怎么说呢?比方说现在要抢小米手机了;中午10点估计会有100万人抢1000个手机;但是你发现有2000个人都抢到手机了;我库存就1000个啊,怎么会有2000个人抢购成功呢?
ok,我们这样想一下;小米的秒杀服务肯定时高可用的对吧;那么它就会有多个点部署应用;那么就会用很多个jvm;而你要操作的资源分布在不同的内存空间当中,这就导致了不可见性;那么我们把它放到统一的资源空间就可以了;然后又为了提高它的性能,我们可以把它放到缓存当中 去,使用分段锁来提高它的性能。
但是,一般对于大多数同学而言,我们的工作内容很少有这个规模的并发量;那么我们再来设计锁的时候需要从以下几个方面考虑:
互斥 我们最需要保证,同一时刻只能有一个线程获得锁,这是最基本的一点。
防止死锁 举例一个死锁的场景,比方说我们在设置完一个锁之后这个时候还没来得及释放锁,redis挂了;导致其它线程都无法获得锁,造成死锁。所以非常有必要设置锁的有效时间,确保系统出现故障后,在一定时间内能够主动去释放锁,避免造成死锁的情况
性能 对于访问量大的共享资源,需要考虑减少锁等待的时间,避免导致大量线程阻塞。
所以在锁的设计时,需要考虑两点。
1、锁的颗粒度要尽量小。比如你要通过锁来减库存,那这个锁的名称你可以设置成是商品的ID,而不是任取名称。这样这个锁 只对当前商品有效,锁的颗粒度小。
2、锁的范围尽量要小。比如只要锁2行代码就可以解决问题的,那就不要去锁10行代码了。
重入
我们知道ReentrantLock是可重入锁,那它的特点就是:同一个线程可以重复拿到同一个资源的锁。重入锁非常有利于资源的高效利用。Reddison里面是用到了RLock。

Redisson原理分析

加锁机制
线程去获取锁,获取成功: 执行lua脚本,保存数据到redis数据库。
线程去获取锁,获取失败: 一直通过while循环尝试获取锁,获取成功后,执行lua脚本,保存数据到redis数据库。
监视器看门狗
它的作用就是一个线程获得锁后,突然服务器宕机了,那么这个时候在一定时间后这个锁会自动释放,你也可以设置锁的有效时间(不设置默认30秒),这样的目的主要是防止死锁的发生。

假如你在实际应用场景中,线程A把锁的有效时间设置为5秒;而中间业务逻辑处理了6秒才会释放锁;这样在释放锁的就会发生异常情况。如果线程A还想持有锁的话,那么就会启动一个watch dog后台线程,不断的延长锁key的生存时间。默认情况下不启动,因为会影响性能。
可重入加锁机制
Redisson可以实现可重入加锁机制的原因,我觉得跟两点有关:
1、Redis存储锁的数据类型是 Hash类型
2、利用Hash结构作为储存单元,将业务指定的名称作为key,将随机UUID和线程ID作为field,最后将加锁的次数作为value来储存。同时UUID作为锁的实例变量保存在客户端。将UUID和线程ID作为标签在运行多个线程同时使用同一个锁的实例时,仍然保证了操作的独立性,满足了线程安全的要求
Redisson分布式锁的缺点
线程A 对某个master节点写入了redisson锁,此时会异步复制给对应的 slave节点。但是这个过程中一旦发 生 master节点宕机,主备切换,slave节点从变为了 master节点。

这时线程B 来尝试加锁的时候,在新的master节点上也能加锁,此时就会导致多个客户端对同一个分布式锁完成了加锁。就导致了脏数据,但是呢这种情况下百分之99的情况都不会发生,如果有脏数据这个数据量也不会太大,人工处理下也可以。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值