秒杀系统架构关键技术-减库存设计

减库存有哪几种方式
1. 下单减库存
2.付款减库存
3.预扣库存
 
减库存可能存在的问题
1.采用“下单减库存”的方式,即用户下单后就减去库存,正常情况下,买家下单后付款的概率会很高,所以不会有太大问题。但是有一种场景例
外,就是当卖家参加某个活动时,此时活动的有效时间是商品的黄金售卖时间, 如果有竞争对手通过恶意下单的方式将该卖家的商品全部下单,让这款商品的库
存减为零,那么这款商品就不能正常售卖了。要知道,这些恶意下单的人是不会 真正付款的,这正是“下单减库存”方式的不足之处。
2.“付款减库存”能解决恶意下单问题但是又会导致另外一个问题:库存超卖。

3.“预扣库存”这种方式确实可以在一定程度上缓解上面的问题。但是没有彻底解决这个问题,虽然把有效的付款时间设置为 10 分钟,但是恶意买家完全可以在 10 分钟后再次下单,或者采用一次下单很多件的方式把库存减完。针对这种情况,解决办法还是要结合安全和反作弊的措施来制止。例如,给经常下单不付款的买家进行识别打标(可以在被打标的买家下单时 不减库存)、给某些类目设置最大购买件数(例如,参加活动的商品一人最多只 能买 3 件),以及对重复下单不付款的操作进行次数限制等。针对“库存超卖”这种情况,在 10 分钟时间内下单的数量仍然有可能超过 库存数量,遇到这种情况我们只能区别对待:对普通的商品下单数量超过库存数 量的情况,可以通过补货来解决;但是有些卖家完全不允许库存为负数的情况, 那只能在买家付款时提示库存不足。

大型秒杀中如何减库存?

目前来看,业务系统中最常见的就是预扣库存方案,像你在买机票、买电影 票时,下单后一般都有个“有效付款时间”,超过这个时间订单自动释放,这都 是典型的预扣库存方案。而具体到秒杀这个场景,应该采用哪种方案比较好呢? 由于参加秒杀的商品,一般都是“抢到就是赚到”,所以成功下单后却不付 款的情况比较少,再加上卖家对秒杀商品的库存有严格限制,所以秒杀商品采 用“下单减库存”更加合理。另外,理论上由于“下单减库存”比“预扣库 存”以及涉及第三方支付的“付款减库存”在逻辑上更为简单,所以性能上更占
优势。 “下单减库存”在数据一致性上,主要就是保证大并发请求时库存数据不能 为负数,也就是要保证数据库中的库存字段值不能为负数,一般我们有多种解决 方案:一种是在应用程序中通过事务来判断,即保证减后库存不能为负数,否则 就回滚;另一种办法是直接设置数据库的字段数据为无符号整数,这样减后库存 字段值小于零时会直接执行 SQL 语句来报错;再有一种就是使用 CASE WHEN 判断语句,例如这样的 SQL 语句: UPDATE item SET inventory = CASE WHEN inventory >= xxx THEN inventory­xxx ELSE inventory END
 
秒杀减库存的极致优化
在交易环节中,“库存”是个关键数据,也是个热点数据,因为交易的各个环节中都可能涉及对库存的查询。但是,我在前面介绍分层过滤时提到过,秒杀中并不需要对库存有精确的一致性读,把库存数据放到缓存(Cache)中,可以大大提升读性能。 解决大并发读问题,可以采用 LocalCache(即在秒杀系统的单机上缓存商 品相关的数据)和对数据进行分层过滤的方式,但是像减库存这种大并发写无论 如何还是避免不了,这也是秒杀场景下最为核心的一个技术难题。
秒杀商品和普通商品的减库存还是有些差异的,例如商品数量比较少,交易 时间段也比较短,因此这里有一个大胆的假设,即能否把秒杀商品减库存直接放 到缓存系统中实现,也就是直接在缓存中减库存或者在一个带有持久化功能的缓 存系统(如 Redis)中完成呢? 如果你的秒杀商品的减库存逻辑非常单一,比如没有复杂的 SKU 库存和总 库存这种联动关系的话,我觉得完全可以。但是如果有比较复杂的减库存逻辑, 或者需要使用事务,你还是必须在数据库中完成减库存。
由于 MySQL 存储数据的特点,同一数据在数据库里肯定是一行存储 (MySQL),因此会有大量线程来竞争 InnoDB 行锁,而并发度越高时等待线 程会越多,TPS(Transaction Per Second,即每秒处理的消息数)会下降,响应时间(RT)会上升,数据库的吞吐量就会严重受影响。 这就可能引发一个问题,就是单个热点商品会影响整个数据库的性能, 导致0.01% 的商品影响 99.99% 的商品的售卖,这是我们不愿意看到的情况。一个 解决思路是遵循前面介绍的原则进行隔离,把热点商品放到单独的热点库中。但 是这无疑会带来维护上的麻烦,比如要做热点数据的动态迁移以及单独的数据库等;
而分离热点商品到单独的数据库还是没有解决并发锁的问题,我们应该怎么办呢?要解决并发锁的问题,有两种办法:
应用层做排队 。按照商品维度设置队列顺序执行,这样能减少同一台机器对数据库同一行记录进行操作的并发度,同时也能控制单个商品占用数据库连接的数量,防止热点商品占用太多的数据库连接。
数据库层做排队 。应用层只能做到单机的排队,但是应用机器数本身 很多,这种排队方式控制并发的能力仍然有限,所以如果能在数据库层做全局排队是最理想的。阿里的数据库团队开发了针对这种 MySQL 的 InnoDB 层上的补丁程序(patch),可以在数据库层上对单行记录做到并发排队。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值