优惠券领劵接口-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只能做递增
场景:商品秒杀、优惠券方法,需要记录库存操作前后的业务
三个方案各有利弊,看业务场景而定