基于redis实现分布式锁

       谈到给代码加锁、代码同步问题,我们都会想到synchronized或者lock,这两种加锁机制虽然可以解决同步问题,但是这种锁是属于JVM级别的,只能适用于单体架构,而分布式应用一般都是部署多台服务器上也就是有多个JVM,

这时synchronized或者lock就没有办法解决,比如一个电商系统里面某个方法要对某件商品进行减库存,这个系统部署在多台服务器上,即使加上了synchronized锁,这时两个人买这个商品同时进来减库存,基于负载均衡可能会出现

两个人的减库存请求访问在两个服务器上,就会出现明明是两个人买同一件商品结果只减了一个库存。这时就要使用分布式锁,目前对于实现分布式锁依赖的中间件主要有三种:redis、数据库(mysql等)、zookeeper,这些中间件

之所以能实现分布式锁是因为无论你这个应用部署在多少台服务器上,都要去访问这些中间件,比如mysql,减库存怎么减都是要访问数据库的,无论多少个请求、从那个服务器进来的请求最后都要汇集于一处,就在这一个集中点

加锁。

    现在就简单介绍下通过redis实现分布式锁,redis里面有一个命令是setnx,这个命令一部分功能和set一样设置一个key,不同的是如果这个key已经存在了,那么就不能设置成功,java里面体现就是会返回一个Boolean类型的值,

设置成功了会返回true,设置不成功(已经有这个key了)会返回false,使用代码实现如下(java里面的setIfAbsent对应的就是redis的setnx),一个分布式锁就实现了

 个屁。。。。。当然没有这么简单啦,这种分布式锁的实现方式还有很多问题。比如在一个线程加锁成功之后再到解锁之前也就是执行32到39行代码之间某一行的时候,服务器宕机了,挂掉了,那这个锁就释放不了,

其他的线程、其他的请求也被挡在外面进不来了,这样就造成死锁,所以这时我们需要给这个锁设置一个有效时间,超出这个有效时间就会自动释放锁,java里面可以这样设置超时时间:

 但是这样又有问题,就是如果在执行完27行代码想要继续执行29行的时候,应用的服务器挂了,还没来得及设置超时时间,那岂不是又要会死锁?所以需要把27行设置锁代码和29行设置时间的代码保证一个原子性,

也就是让它们要么一起成功,要么一起失败,事实上redis里面支持可以一行代码实现这个操作,也就是保证key的设置和有效时间的原子执行,代码如下:

这样就能避免死锁情况的发生了。

然而即便如此以上实现分布式锁还是会有问题,因为锁的有效时间设置为10s,但万一下面的业务代码执行时间超过了10s呢?这时候自动释放锁了其他线程又可以重新加锁,这时又发生了两个线程同时执行业务代码又有安全问题了,

而且在后来的那个线程执行完之前,前面那个线程走到了最后那行释放锁的代码,这样就把后面来的线程设置的锁给释放掉了,这时又有其他线程进来能加锁成功。。。。。如此反复,那这个锁基本就相当于无效。

这时我们需要引入一个强大的高级的分布式协调 Redis 客服端------redisson,引入jar包和初始化对redis的连接

 

 具体代码实现如下:

 

这个lock方法里面就能解决上面的几个 问题,如一个线程设置的锁被另一个线程释放,这种情况在上面的方法里面不会,unlock里面会判断当前想要释放锁的线程和当初加锁的线程是不是同一个,是同一个才能释放;

它还可以实现锁续命,也就是看门狗(watch dog)机制,简而言之就是每隔一段时间(约为设置锁时间的三分之一)就开启一个线程去判断当前线程是否还持有这个锁,如果还有那么就对这个锁进行续命,

也就是延长锁的有效时间,自此,一个完整且有一定安全性的的分布式锁就完成了。

而redisson之所以能实现这些操作是因为里面许多原子操作都是使用lua脚本实现的,例如加锁的时候如下:

 它把设置key、有效时间这些操作放在一个脚本里面执行,实现了原子性,而又因为redis的单线程操作命令所以使得在执行这些命令的时候不会有并发问题,它的具体流程如下:

 以上实现分布式锁其实依旧有问题,就是比如上面线程1加锁成功,redis里面的Master节点已经把key设置进去了,但在进行相关信息同步到Slave(主从复制)的过程中,Master节点挂了,key还没有同步过去,

这时线程2就能加锁成功,又出现了两个线程同时执行加锁代码块了。这时需要用到另一种加锁机制,redLock或者zookeeper,它们的加锁机制很类似,就是设置锁的时候,必须要这集群里面有三分之二以上的节点

都设置了锁才算成功,比如有三个redis节点,必须要2个都设置了锁才能算加锁成功,这样能很大限度的避免其中一个挂了导致的锁失效问题,当然这样性能就比不上只要一个节点设置锁就算成功的机制。

以上实现分布式锁来源于图灵学院诸葛老师视频讲解,感谢诸葛老师。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值