当前位置: 代码迷 >> 综合 >> 诡异的【库存重复扣减】问题
  详细解决方案

诡异的【库存重复扣减】问题

热度:87   发布时间:2024-02-23 09:22:36.0

背景:

业务场景:库存扣减场景,消费方调用dubbo服务,扣减订单的库存

Dubbo配置:5s超时时间,未配置默认重试次数

消费方:对商品加redis分布式锁,防止并发扣减,失效与超时时间为10s

问题:用户对相同商品的订单,同时发起扣减库存请求,造成了未扣减,或同一订单多扣减的情况

疑惑:未扣减可能是失败了,但为什么会同一订单多扣减?明明加了redis锁啊!

 

但问题,就出在redis锁上

 

复现:

1.大量相同商品扣减请求发出

2.消费方对一笔订单A的商品加锁,其他订单请求进来后redis等待

4.当订单量巨大,必然会造成订单B的redis等待超时(10s),此时dubbo请求超时(5s)

5.另一方面,由于当前大量线程不断进入并持续等待,造成cpu迟缓,当前订单A库存的操作时间变长,便可能造成扣减库存变长(7s),订单Adubbo请求超时(5s),而此时订单A仍在扣减库存

6.订单B重试2次,均未抢到锁,扣减失败

7.订单A扣减1次后,由于重试,再次扣减1次,甚至2次

 

分析:

经过情景复现,可以知道,由于

1.dubbo的默认重试机制

2.redis锁的等待超时

最终造成了这种情况,如何避免呢?

 

避免:

dubbo:

1.对非幂等性接口,dubbo不进行重试

2.对于库存扣减这种操作,消费方不关心操作结果,操作成败与否的重任交给服务方,所以dubbo请求超时时间可以定位100ms甚至更低

 

消费方:

1.服务方接口添加幂等性校验:如通过redis锁对订单号加为期10s的锁(时间可结合业务),尽量防止重复请求与并发

2.引入失败重试机制,对redis超时或扣减失败的订单数据进行记录,利用定时任务等机制重试1-2次。提高系统的容错性与性能

 

问题:

上面的复现中,我们提到了可能的重复扣减的可能性场景,但结合我所遇到的问题,依然遗留下两个问题:

1.dubbo默认重试机制是2次,加上第一次的请求,一共是3次,但我看到共有4次该订单的请求,十分不解!

2.在【复现】中模拟的重复扣减场景里,按理重复的扣减应该是间隔1-5s左右的时间间隔,但重复的扣减记录却是相同的扣减时间,难道在redis锁下,并发了?不解...

 

如果有大佬看到此处,麻烦提出您的意见和建议,感谢?....

  相关解决方案