分布式锁介绍

什么是分布式锁?

例如一些抢票业务,要判断库存,那必定就要加锁,由于锁属于jvm,集群部署下面多个jvm的锁不一样,单体项目没关系,集群就锁不住,这里就需要公共锁,也就是分布式锁。

setnx分布式锁原理

 

先读完下图。

问获取锁为什么要写这么长的命令呢? 答案:是为了实现原子性。

又问,不设置超时时间不就得了? 答案:不行,有死锁的可能,万一setnx锁住后程序挂了,setex执行不到,这里锁就永远无法释放。

4cba1492b22048d6a3c7114cfb2c1b2d.png再问:

505c2a1ab27a4099a70bc43d64fe534c.png

答: 假如锁的过期时间过短,加锁后,业务执行时间超过了锁的过期时间,业务没执行完,锁就释放了,其他线程就能来获取锁,又会存在线程安全问题。

假如锁的过期时间较长,业务性能会降低。

这里有两种执行方案

  1. 根据业务预估锁的过期时间(不靠谱,有很多不稳定因素影响这个时间,例如网络卡顿、资源等待等)

  2. 给锁续期,再创建一个监控线程,监控业务执行了多久,如果查到业务没执行完锁快过期了,就给锁续期。(自己去实现太麻烦了,还好市面上给了实现方案redisson

redisson分布式锁原理

也是基于setnx的命令,但是做了很多增强和优化。

先来看看基本的操作,用户对某数据加分布式锁,如果不设置过期时间默认是30s,加锁成功后会有一个“看门狗”线程出现,会每隔“过期时间/3”的时间进行锁续期,假如这里过期时间是30s,那每10s就判断一下业务完成没,没完成就重新续期为30s。

看门狗也会随着锁的主动释放而停止工作。

696676c7e404443bbcb7dbd65a7d1466.png这里与setnx还有不同的地方,那就是重试机制

  其他人来获取锁不成功的时候,会通过while循环不断尝试获取锁,当然不用担心他一直卡这里,有执行次数约束,循环一定次数还没获取成功就不尝试了。而且真实业务的执行一般几十毫秒就完成了,不会让其他的线程等太久,这样的设计增加了高并发场景下锁的使用性能。

6b89e623c8fb4848a0a54ccf05701e71.png我们来看一段redisson的代码

第一行getLock就是获取锁的操作。

tryLock两个参数时,第一个参数是循环获取锁的时间,下图超过了10s就代表获取锁失败。这里有看门狗机制,默认锁过期时间是30s。

tryLock三个参数时,第一个参数和上面一样。第二个代表锁过期时间,这时不会有看门狗机制,因为系统认为你自己设置了过期时间,你对业务执行时间有预估,可以自己控制锁的释放时间,无需看门狗帮忙。

(提醒一点,加锁、设置过期时间底层都是通过lua脚本完成的,lua脚本能够调用多条redis命令,保证redis多条命令的原子性。)

第一行代码上面还有个重入锁,这里接着往下看。

8328355af39a41a099640bdbad92737d.png

什么是重入锁

在业务粒子细度比较大的时候,不同函数可能相互调用,例如下图,一个线程内方法一里面逻辑加锁,执行业务,业务里面调用方法二,方法二加同一把锁,如果能加成功,代表可重入,否则不是。

48401586bfcb45a2890a20512616ce65.png

如何实现重入锁呢?

我们可以用redis里面的hash结构,key是自己锁的名字,field是线程id,value是加锁的次数,例如上图add1加了一次锁,那么value是1,add2加锁时value变成2,当释放锁的时候就不再是直接删除key了,而是value--,判断value是否为0,0就删除key。

d22430847e5f4f939ddad6cd851b4fc5.png

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

.ccc.。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值