学习笔记:分布式锁

序言

hi,大家好~刚看完s10比赛,恭喜SN3:1战胜JDG,今天我们聊一下分布式锁,希望大家可以点个赞支持一下O(∩_∩)O

分布式锁的产生:随着互联网的发展,单体架构无法满足需求,从而扩展成分布式架构后解决分布式情况下同步问题所产生的技术。

为什么分布式情况下要使用分布式锁来解决同步问题呢?

  • 我们知道在程序中是离不开线程安全的,在单体架构下我们可选择的解决线程安全的方案有很多,最常见的就是使用互斥锁来解决,但在分布式集群环境下,使用常规的互斥锁例如:synchronized,lock是无法控制多台机器的,它们只能控制单台机器,因此在分布式集群下,单单使用常规的互斥锁是无法保证线程安全的。

举个例子:

  • 现在有两台扣减库存的机器A和B,数据库中库存只剩下1个,这时两个请求同时到达,通过nginx分别负载到了两台不同的机器上,两台机器都使用了synchronized来修饰代码块,两个请求分别获取到了A机器和B机器上的锁,就相当于他俩同时进入了同步代码快,做参数校验库存此时>0,于是两台机器都做了减库存的操作,这就最终导致了超卖的情况发生。

分布式锁

分布式锁就是用来解决上述所发生的的问题的。

分布式锁可以通过redis和zookeeper来实现,今天我们就先聊一下redis的实现。

  • redis中有一个setnx命令,它代表的意思是,如果设置的key不存在则设置成功返回true,如果存在则设置不成功返回false,redis的分布式锁就是基于这个命令的,无论集群有多少台,最终只会有一台机器可以返回true,来实现“唯一的锁”。

常见的问题

  • 如果程序发生异常,锁释放不了怎么办?

答:释放锁的代码需放到finally中执行。

  • 如果机器宕机,锁释放不了怎么办?

答:这就需要我们为锁设置过期时间了,保证宕机后锁还能被释放。
(注意,设置锁和设置过期时间的命令需通过一条指令实现,保证原子性,否则设置完锁宕机了还没来得及设置过期时间,锁就释放不了了,可以通过spring封装的StringRedisTemplate的setIfAbsent方法实现)

  • 如果A线程释放了B线程的锁怎么办?

场景描述:A线程加锁成功,但是业务执行时长超过了锁的存活时间,锁自动释放,B线程加锁成功后,A线程业务终于执行完了,此时A线程要释放掉锁,它就会把B线程的锁给释放掉了。

解决方法:每次加锁时,可以通过UUID生成一个随机的VALUE,在释放锁的时候判断一下锁当中的VALUE和随机生成的VALUE是否相同,相同的话说明是自己的锁然后进行释放。

  • 如果业务执行时间大于锁的释放时间怎么办?

答:我们可以再启动一个线程,定时为我们的锁增加存活时间,直到释放锁时就可以关闭该线程

  • 在主从架构下,主库宕机了,但锁的信息还没同步给从库,此时一个从库当选成为新的主库,就可能会出现两个请求同时执行的情况

答:这时我们就需要设置,从库延迟重启了,延迟的时间可以设置为锁的存活时间,牺牲掉一些请求从而保证程序的安全性,避免发生两个请求同时执行的情况。

优化

我们知道锁这个东西有利有弊,在保证了并发安全的情况下降低了程序的执行效率,所以我们可以针对不同的业务场景做优化。

eg:有这么一个业务,对某一商品进行库存扣减时用到了分布式锁。

我们可以采用分段锁的思想来进行优化,比如现在有20件库存,我们将它拆分到4个库中,每个库存放5件库存,这样我们的并发就能足足提升4倍了。

分布式锁的封装

现有市面上有很多基于redis的分布式锁框架,最常见的就是Redisson了,使用Redisson可以很方便的使用分布式锁,它的底层基本和上述差不多。

  • 使用方法:
  • 第一步:导入Redission依赖
   	<dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.6.5</version>
        </dependency>
  • 第二步:直接注入Redisson
    @Autowired
    private Redisson redisson;
  • 第三步:添加锁,释放锁
 String key="分布式锁";
 RLock lock = redisson.getLock(key);//获取锁
 lock.lock(30, TimeUnit.SECONDS);//添加锁
 lock.unlock();//释放锁
  • redis集群环境下,Redisson的使用

使用宏锁(传入的锁有一半加锁成功,则整体加锁成功),优化redis集群情况下,数据延迟同步问题导致的同时2个用户加锁成功

RLock lock1 = redisson.getLock(key);//获取锁
RLock lock2 = redisson.getLock(key);//获取锁
RedissonRedLock redissonRedLock=new RedissonRedLock(lock1,lock2);//设置宏锁
redissonRedLock.lock();//添加锁
redissonRedLock.unlock();//释放锁

结束语

以上就是redis分布式锁的实现和一些注意事项啦,如果您觉得哪里可以优化的话,可留言一起讨论哦,哈哈我是一个努力向上的小白,您的点赞支持就是对我持续创作的最大动力!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

guojunjiang12345

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

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

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

打赏作者

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

抵扣说明:

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

余额充值