概述
秒杀的核心关注是商品库存,有限的商品在同一时间被多个请求同时扣减,卖不出去是个问题,超卖更是个问题。要保证准确性,显而易见是一个难题。秒杀场景下的一致性问题,主要就是库存扣减的准确性问题。
减库存的方式
电商场景下的购买过程一般分为两步:下单和付款。“提交订单”即为下单,“支付订单”即为付款。
减库存方式基本有以下几种方式
- 下单减库存。买家下单后,扣减商品库存。
- 付款减库存。买家下单后,并不立即扣减库存,而是等到付款后才真正扣减库存。但因为付款时才减库存,如果并发比较高,可能出现买家下单后付不了款的情况,因为商品已经被其他人买走了。
- 预扣库存。买家下单后,库存为其保留一定的时间(如 15 分钟),超过这段时间,库存自动释放,释放后其他买家可以购买。
减库存的问题
下单减库存
优势:用户体验最好。下单减库存是最简单的减库存方式,也是控制最精确的一种。下单时可以直接通过数据库事务机制控制商品库存,所以一定不会出现已下单却付不了款的情况。
劣势:可能卖不出去。正常情况下,买家下单后付款概率很高,所以不会有太大问题。但有一种场景例外,就是当卖家参加某个促销活动时,竞争对手通过恶意下单的方式将该商品全部下单,导致库存清零,那么这就不能正常售卖了。恶意下单的人是不会真正付款的,这正是 “下单减库存” 的不足之处。
付款减库存
优势:一定实际售卖。“下单减库存” 可能导致恶意下单,从而影响卖家的商品销售, “付款减库存” 由于需要付出真金白银,可以有效避免。
劣势:用户体验较差。用户下单后,不一定会实际付款,假设有 100 件商品,就可能出现 200 人下单成功的情况,因为下单时不会减库存,所以也就可能出现下单成功数远远超过真正库存数的情况,这尤其会发生在大促的热门商品上。如此一来就会导致很多买家下单成功后却付不了款,购物体验自然是比较差的。
预扣库存
优势:缓解了以上两种方式的问题。预扣库存实际就是“下单减库存”和 “付款减库存”两种方式的结合,将两次操作进行了前后关联,下单时预扣库存,付款时释放库存。
劣势:并没有彻底解决以上问题。比如针对恶意下单的场景,虽然可以把有效付款时间设置为 10 分钟,但恶意买家完全可以在 10 分钟之后再次下单。
实际如何减库存
业界最为常见的是预扣库存。无论是外卖点餐还是电商购物,下单后一般都有个 “有效付款时间”,超过该时间订单自动释放,这就是典型的预扣库存方案。
预扣库存还需要解决恶意下单和避免超卖的问题。
恶意下单
结合安全和反作弊措施来制止。
- 识别频繁下单不付款的买家并进行打标,这样可以在打标买家下单时不减库存
- 为大促商品设置单人最大购买件数,一人最多只能买 N 件商品
- 对重复下单不付款的行为进行次数限制阻断。
避免超卖
对于普通商品,秒杀只是一种大促手段,即使库存超卖,商家也可以通过补货来解决。而对于一些商品,秒杀作为一种营销手段,完全不允许库存为负,也就是在数据一致性上,需要保证大并发请求时数据库中的库存字段值不能为负。
- 通过事务来判断,即保证减后库存不能为负,否则就回滚。
- 直接设置数据库字段类型为无符号整数,这样一旦库存为负就会在执行 SQL 时报错。
- 使用 CASE WHEN 判断语句:UPDATE item SET inventory CASE WHEN inventory xxx THEN inventory xxx ELSE inventory
性能的优化
库存是个关键数据,更是个热点数据。对系统来说,热点的实际影响就是 “高读” 和 “高写”,也是秒杀场景下最为核心的一个技术难题。
高并发读
秒杀场景解决高并发读问题,关键词是“分层校验”。在读链路时,只进行不影响性能的检查操作,如用户是否具有秒杀资格、商品状态是否正常、用户答题是否正确、秒杀是否已经结束、是否非法请求等,而不做一致性校验等容易引发瓶颈的检查操作。直到写链路时,才对库存做一致性检查,在数据层保证最终准确性。
在分层校验设定下,系统可以采用分布式缓存甚至 LocalCache 来抵抗高并发读。即允许读场景下一定的脏数据,这样只会导致少量原本无库存的下单请求被误认为是有库存的,等到真正写数据时再保证最终一致性,由此做到高可用和一致性之间的平衡。
分层校验的核心思想是:不同层次尽可能过滤掉无效请求,只在“漏斗” 最末端进行有效处理,从而缩短系统瓶颈的影响路径。
高并发写
缓存
秒杀商品和普通商品的减库存是有差异的,核心区别在数据量级小、交易时间短,如果减库存逻辑非常单一的话,可以直接在一个带有持久化功能的缓存中进行减库存操作。
如果有比较复杂的减库存逻辑,或者需要使用到事务,那就必须在数据库中完成减库存操作。
优化DB性能
库存数据落地到数据库实现其实是一行存储(MySQL),因此会有大量线程来竞争 InnoDB 行锁。但并发越高,等待线程就会越多,TPS 下降,RT 上升,吞吐量会受到严重影响。
排队
通过缓存加入集群分布式锁,从而控制集群对数据库同一行记录进行操作的并发度,同时也能控制单个商品占用数据库连接的数量,防止热点商品占用过多的数据库连接。
最后
以上就是舒心小刺猬为你收集整理的闲谈秒杀系统(二)解决一致性问题的全部内容,希望文章能够帮你解决闲谈秒杀系统(二)解决一致性问题所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复