这是悟空的第 108 篇原创文章前端
做者 | 悟空聊架构sql
来源 | 悟空聊架构(ID:PassJava666)数据库
转载请联系受权(微信ID:PassJava)后端
你好,我是悟空。缓存
上篇谈到了秒杀设计的方案:微信
今天咱们来探讨下扣减库存
的方案。并发
生活中,咱们老是用各类电商 APP 抢购商品,可是库存数是不多的,特别是秒杀场景,商品可能就一件,那如何保证不会出现超卖的状况呢?分布式
1、扣减库存的三种方案
1.1 下单减库存
用户下单时减库存高并发
优势:实时减库存,避免付款时因库存不足减库存的问题
缺点:恶意买家大量下单,将库存用完,可是不付款,真正想买的人买不到
1.2 付款减库存
下单页面显示最新的库存,下单时不会当即减库存,而是等到支付时才会减库存。
优势:防止恶意买家大量下单用光库存,避免下单减库存的缺点
缺点:下单页面显示的库存数可能不是最新的库存数,而库存数用完后,下单页面的库存数没有刷新,出现下单数超过库存数,若支付的订单数超过库存数,则会出现支付失败。
1.3 预扣库存
下单页面显示最新的库存,下单后保留这个库存一段时间(好比10分钟),超过保留时间后,库存释放。若保留时间事后再支付,若是没有库存,则支付失败。
优势:结合下单减库存的优势,实时减库存,且缓解恶意买家大量下单的问题,保留时间内未支付,则释放库存。
缺点:保留时间内,恶意买家大量下单将库存用完。并发量很高的时候,依然会出现下单数超过库存数。
2、如何解决恶意买家下单的问题
这里的恶意买家指短期内大量下单,将库存用完的买家。
2.1 限制用户下单数量
优势:限制恶意买家下单
缺点:用户想要多买几件,被限制了,会下降销售量
2.2 标识恶意买家
经过标识用户的设备 id 或者会员 id,将用户加入黑名单,不足之处是有些用户是模拟的,识别不出来是否是真正的恶意买家。
3、如何解决下单成功而支付失败(库存不足)的问题
3.1 备用库存
商品库存用完后,若是还有用户支付,直接扣减备用库存。
优势:缓解部分用户支付失败的问题。
缺点:备用库存只能缓解问题,不能从根本上解决问题。另外备用库存针对普通商品能够,针对特殊商品这种库存少的,备用库存量也不会很大,仍是会出现大量用户下单成功却因库存不足而支付失败的问题。
4、如何解决高并发下库存超卖的场景
库存超卖最简单的解释就是多成交了订单而发不了货。
场景
用户 A 和 B 成功下单,在支付时扣减库存,当前库存数为 10。因 A 和 B 查询库存时,都还有库存数,因此 A 和 B 均可以付款。
A 和 B 同时支付,A 和 B 支付完成后,能够看作两个请求回调
后台系统扣减库存,有两个线程处理请求,两个线程查询出来的库存数 inventory = 10
。
而后 A 线程更新最终库存数 :
lastInventory = inventory - 1 = 9,
B 线程更新库存数:
lastInventory = inventory - 1 = 9。
而实际最终的库存应是 8 才对,这样就出现库存超卖的状况,而发不出货。
那如何解决库存超卖的状况呢?
如下方案都是基于数据库层面的。有些同窗可能会问,是否是能够用 Redis 分布式锁来,后面会讲到。
方案一
SQL语句直接更新库存,而不是先查询出来,而后赋值
UPDATE [库存表] SET 库存数 - 1
方案二
SQL语句更新库存时,若是扣减库存后,库存数为负数,直接抛异常,利用事务的原子性进行自动回滚。
方案三
利用SQL语句更新库存,防止库存为负数
UPDATE [库存表] SET 库存数 - 1 WHERE 库存数 - 1 > 0
若是影响条数大于1,则表示扣减库存成功,不然不更新库存,并退款。
5、秒杀场景下如何扣减库存
5.1 采用下单减库存
因秒杀场景下,大部分用户都是想直接购买商品的,能够直接用下单减库存。
大量用户和恶意用户都是同时进行的,区别是正经常使用户会直接购买商品,恶意用户虽然在竞争抢购的名额,可是获取到的资格和普通用户同样,因此下单减库存在秒杀场景下,恶意用户下单并不能形成以前说的缺点。
并且下单直接扣减库存,这个方案更简单,在第一步就扣减库存了。
5.2 Redis 缓存
查询缓存要比查询数据库快,因此将库存数放在缓存中,直接在缓存中扣减库存。
若是并发很高,还能够采起分布式锁的方案。分布式锁能够参考我以前写的两篇文章:
5.3 限流
秒杀场景中,对请求作了不少限流操做,好比前端页面的限流和后端令牌桶限流,真正到扣减库存那一步时,请求数不多了。因此限流经常使用在秒杀方案中,感受能够再写一篇限流的文章了~
另外其实真实的项目中,用到了更多的机制来保证可以正常扣减库存,本篇是抛砖引入,但愿你们提出宝贵的建议和方案~。
赠送一张秒杀场景方案总结:
- END -
写了两本 PDF, 回复 分布式 或 PDF 下 载。
个人 JVM 专栏已上架,回复 JVM 领取
我是悟空,努力变强,变身超级赛亚人!
本文分享自微信公众号 - 悟空聊架构(PassJava666)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。