分布式锁有什么用,如何实现分布式锁

现在我们的项目进行秒杀活动,因为用户量比较多,需要进行多线程操作,在不加锁的情况下,容易产生超卖现象,当只有一个库存时,多个用户(多线程)同时检查库存,发现库存充足,但在下单之前都没有进行排他性的校验和扣减库存操作,从而导致超卖。

初步改造是加了一把同步锁(http://t.csdnimg.cn/h6ngY),当进行秒杀业务时,第一个线程正在执行,其他的线程同时进来会产生互斥,需要排队等待,需要等持有锁的线程释放了,才可以正常的进行运行处理。但是随着用户量的如意增多,会产生服务器压力变大的现象,性能到达了瓶颈。(同步锁产生瓶颈的原因:http://t.csdnimg.cn/P0u08)。

这时,引入了Ngnix负载均衡,讲服务器进行水平扩展,通过Nfnix进行分布式集群部署,但是在压测的时候发现,吞吐量确实上来了,但是秒杀功能又会出现超卖问题。这又是什么原因呢?

经过研究发现,这个时同步锁的问题,同步锁时JVM级别的,只能够锁住单个进程,但是经分布式部署之后每台服务器只能锁住一个进程,因为有多台服务器,所以会产生超卖现象。 

这时,我们可以引入分布式锁(http://t.csdnimg.cn/3gm1z)(redis和zookeeper)来解决这个问题了。这里我们讲解使用redis实现分布式锁。

咱们可以使用redis中的SetNX来实现分布式锁,SetNX的特性是:“当一个线程进来往redis的当中通过SetNX去存储一个值的时候,如果发现一个键里面(这里统称为A键)没有值得时候,他会往里面存储一个值并且返回true,当第二个线程进来准备往A键存储值的时候,发现有值,此时会返回false。”通过SetNX的这个特性,就可以实现分布式锁。

当用户请求进来的时候,通过SetNX来设置一个键,这个键里面没有的时候返回true,加锁成功(这里要加上过期时间,因为用户在请求的过程中的,如果此时服务器挂掉了,那么其他的服务器正常的请求依然会出现一个阻塞的情况。因为其他服务器的线程通过SetNX来进行上锁的时候,会发现这个键当中会一直有值,所以说会永远不会上锁成功,之前挂掉的服务器会一直持有锁,从从而造成一个死锁的现象。加上过期时间,当服务器挂掉了,可以等时间到了之后,进行锁的释放,从而不影响其他服务器的正常请求)。

通过setNX,在用户请求进来加上锁,其他所有服务器的线程此时再通过SetNX会发现已经无法进行上锁了,需要等待锁的释放。只有当第一个线程处理完之后,锁释放之后才能进行第二个线程的运行。 

但是随着业务的扩展会爆露出另外的一些问题,当业务的处理时间超过了这把锁的过期时间业务还没有处理完,这把锁会自动释放,其他的线程此时就会趁虚而入,线程一处理完了之后,此时释放的是线程二的锁,其他的线程又会趁虚而入,以此类推,从而造成超卖的现象。

这里其实是两个问题:

第一个问题是当锁的过期时间到了,业务代码还没有执行完成,是一个锁的过期时间的问题。

第二个问题是在第一个问题的基础上,当业务代码处理完之后,由于其他线程的趁虚而入,而导致释放了其他线程的锁。

 这里又引入了Redisson,完美解决了这个问题。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小小懒懒

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

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

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

打赏作者

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

抵扣说明:

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

余额充值