高并发超发优惠券问题

优惠券领劵接口-Jmeter压测扣超发优惠券问题暴露

简介:Jmeter压测领劵接口-超发优惠券问题暴露

  • 新建接口压测计划

  • 压测领劵接口

  • 完成xml编写

    <!--扣减库存-->
        <update id="reduceStock">
            update coupon set stock=stock-1 where id = #{couponId}
        </update>
    
  • 问题

    • 扣减存储为负数,超发优惠券
    • 给公司造成资损
高并发下怎样优雅的保证扣减库存数据的正确性

简介:高并发下扣减库存的常见解决方案介绍

  • 这里不谈秒杀设计,不谈使用队列等使请求串行化,

    • 秒杀的话:限流、队列、异步,可以看小滴课堂专题视频
  • 我们谈下怎么用锁来保证数据正确,防止超发导致库存是负数,你能下想几种方式

    先看下面的是精简版的时序图

    • 同步代码块synchronized ,lock
    public synchronized void reduceCouponStock(long couponId ,Integer num) {
    //业务逻辑
    }
    
    问题:synchronized 作用范围是单个jvm实例, 如果做了集群分布式等,就失效了,且单机JVM加锁后就是串行等待问题
    
    • 分布式锁 zookeeper,redis (后续会讲到分布式锁的知识)
    可以解决问题
    
    问题:过于笨重,性能有所下降
    
    • 直接数据库更新扣减
    update coupon set stock=stock - #{num} where id = #{couponId} and stock>0
    //测试如果num大于已有库存,则会变负数
    update coupon set stock=stock - #{num} where id = #{couponId} and (stock - #{num})>=0
    或者
    update coupon set stock=stock - #{num} where id = #{couponId} and stock >= #{num} 
    //修复了负数问题
    
    
    • 如果扣减最多1个,则直接使用这种就行
    update coupon set stock=stock-1 where id = #{couponId} and stock>0 
    
    延伸
    update coupon set stock=stock-1 where id = #{couponId} and stock = #{oldStock}
    问题:扣减库存,如果别人补充库存,就存在ABA问题,看业务是否有这个限制,大课采用上面那种
    比如
    C线程查出来是10个
    A线程扣减1个,剩9个
    B线程更新了库存,变回10个
    C更新的时候发现还是10个,则更新成功, 所以避免这个问题,要求不管谁修改了库存,一定要加个version递增版本号
    
    update coupon set stock=stock-1,version=version+1 where id = #{couponId} and stock>0 and versoin=#{oldVersion}
    
  • 代码编写

<!--扣减库存,如果别人补充库存,则可能存在ABA问题-->
    <update id="reduceStock">
        update coupon set stock=stock-1 where id = #{couponId} and stock>0
    </update>
大厂面试热身赛-天猫超市-二面面试题-P7技术专家岗

简介:大厂面试题,高并发库存扣减超卖问题解决,多种sql适合场景

  • 题目:高并发库存扣减超卖问题,很多人加了乐观锁版本号去解决,那下面三种有什么区别,分别适合哪些场景使用
1)update product set stock=stock-1 where id = 1 and stock>0

2)update product set stock=stock-1 where stock=#{原先查询的库存}  and id = 1 and stock>0

3)update product set stock=stock-1,versioin = version+1 where  id = 1 and stock>0 and version=#{原先查询的版本号} 
  • 答案 : 核心是解决超卖的问题,就是防止库存为负数
方案一:id是主键索引的前提下,如果每次只是减少1个库存,则可以采用上面的方式,只做数据安全
校验,可以有效减库存,性能更高,避免大量无用sql,只要有库存就也可以操作成功.
场景:高并发场景下的取号器,优惠券发放扣减库存等


方案二:使用业务自身的条件做为乐观锁,但是存在ABA问题,对比方案三的好处是不用增加version版本字段。如果只是扣减库存且不在意ABA问题时,则可以采用上面的方式,但业务性能相对方案一就差了点,因为库存变动后sql就会无效


方案三:增加版本号主要是为了解决ABA问题,数据读取后,更新前数据被别人篡改过,version只能做递增
场景:商品秒杀、优惠券方法,需要记录库存操作前后的业务


三个方案各有利弊,看业务场景而定
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ITzhongzi

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

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

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

打赏作者

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

抵扣说明:

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

余额充值