Redis分布式锁在高并发环境下的超卖问题

先看这样一段代码,购买商品,扣减库存的逻辑代码

当用户下单,并且调用扣减库存的接口时,先判断商品库存是否还有,因为是秒杀场景下,太多请求都打到数据库,可能会导致数据库崩溃,所以会使用redis缓存,保存商品库存数。

由于是微服务架构,为了实现高并发,我们的商品业务代码(包含库存这部分的代码)不可能只部署在一台服务器上,肯定会在多台服务器上都运行。

场景:

假设:当多个请求同时执行到从redis缓存中取库存值的时候,stock=100,判断库存>0成立,然后进行下面的逻辑,当扣减1个库存时,都会把stock=99写回redis缓存的时候,这时,明明卖了2个,但是redis缓存中的数据stock却等于99,就超卖了。

改进:

我们使用同步代码块,使用Java的synchronized锁,只能解决商品业务代码部署在一台部署上的场景,因为synchronized锁是JVM进程级别的锁,对于多台服务器部署的场景,每台服务器都可以获得它的进程的synchronized锁,还是不能解决微服务架构下的超卖问题。

继续改进:

我们使用redis提供的原生命令setnx实现分布式锁(Java客户端jedis提供的方法setIfAbsent和原生命令setnx是一样的),这个锁加在了redis服务器上,一次只有一个请求能获得,当代码执行完成后,释放锁。好像解决了超卖问题,但是如果代码执行到中间时,代码抛出异常了,锁就一直存在在redis中,其他服务永远无法进入redis,就死锁了。

继续改进:

使用try...finally,就算代码中间抛了异常,也能将锁释放掉。

但是当服务器执行到中间,服务器挂掉了,锁还是不会释放,怎么办?

继续改进:

一般会给锁设置一个超时时间,就算服务器挂掉了,redis服务器中的锁还是会自动释放。

但是,当服务器获取了锁之后,正准备设置超时呢,由于是两条命令分开执行,还是可能会突然服务器挂了,是有可能没设置成功超时时间的,这把锁还是永远在redis中

所以一般使用一条命令,设置锁的同时设置超时时间,发送到redis服务器。

继续改进:

这样好像就没啥问题了,但是在高并发场景下,接口的响应可能会变慢。

当一个请求获取到锁时,处理业务时间由于超过了10s,还没有完成扣减库存,锁过了10s,自动释放了,由于高并发场景下,同时有源源不断的请求过来,其他请求就获得了锁,这时,又会导致超卖问题。这时,可能不只是超卖一个两个的问题,第二个请求加锁成功后,如果第一个请求完成了,执行 解锁 操作,会把第二个请求加的锁给释放掉了,其实这时第二个请求还没执行完成,然后请求三又会获得锁,造成一系列的超卖问题。

造成这个问题的原因,就是线程1把线程2的锁给释放掉了,线程2把线程3的锁给释放掉了,锁一直失效。

继续改进:

中小公司,当并发量不是特别大的时候,是没问题的。

但是这段代码仍然存在线程1加的锁,当线程1没执行完成,锁自动超时释放的情况。在高并发场景下,其他请求又可以获得锁,进入扣减库存操作了,一旦重复扣减同一个数字,又造成超卖问题了。

解决方案:

当线程1获得锁之后(假设设置超时时间t = 30s),在当前线程1的代码内部会开辟一个异步线程2,每过10s (1/3*t) 就会检查线程1是否执行完毕,当线程1还没执行完毕,异步线程2就会重新把这个锁的超时时间设置成30s,这个机制叫watchDog。

异步线程2为什么能获得这个锁的使用权?因为redis的分布式锁是可重入锁,线程2在线程1内部,能直接获得redis中的这个锁。



这个watchDog的机制自己实现起来比较复杂,所以推荐使用Redisson分布式锁。

Redisson分布式锁的实现机制就是基于以上这些逻辑。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

#学习的路上

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

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

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

打赏作者

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

抵扣说明:

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

余额充值