The following article is from 科技缪缪 Author 科技缪缪
一个愤世嫉俗,脱离低级趣味的人
(给ImportNew加星标,提高Java技能)
转自:科技缪缪(本文来自作者投稿)
秒杀这个话题到现在来说已经是一个老生常谈的话题了,不过因为又临近一年一度的双 11,而且发现前段时间无论是阿里还是腾讯一些大厂其实还是在频繁的问到这个场景题,所以还是准备拿出来说说。
秒杀从规模上来说可以分为大秒和小秒。大秒指的是比如双 11 这种特定的节日,商品规模超大、价格超低、流量超大的这种类型活动,小秒一般指的是商家自己配置的一些时段类型的活动,由商家自己指定时间上架。从形式来说还可以分为单时段秒杀和多时段秒杀。但是在这个场景里,我们一般就是指的单时段大型秒杀。
秒杀设计要面对的压力和难度有几点:
怎么保证超高的流量和并发下系统的稳定性?如果峰值的 QPS 达到几十万,面对巨大的流量的压力系统怎么设计保证不被打崩?
怎么保证数据最终一致性?比如库存不能超卖,超卖了那亏本的要么就是商家要么就是平台,用户反正不背这个锅,超卖了就今年 325 预订。
当然,涉及到这种大型的活动,还需要考虑到数据统计分析,总不能活动做完了,效果不知道怎么样。
假设今年的双 11 预估峰值 QPS 将会有 50 万(我随便扯的),而根据我们平时的经验单机 8C 8G 的机器可以达到 1000 左右的 QPS,那么从理论上来说我们只要 500 台机器就可以抗住了,就有钱任性不行?这么设计的话只能出门右转不送了。
本质上,参与秒杀的用户很多,但是商品的数量是有限的,真正能抢到的用户并不多,那么第一步就是要过滤掉大部分无效的流量。
做完无效流量的过滤,那么可能你的无效请求已经过滤掉了 90%,剩下的有效流量会大大的降低系统的压力。之后就是需要针对系统的性能做出优化了。
经过这两步之后,最终我们的流量应该是呈漏斗状。
秒杀除开高并发高流量下的服务稳定性之外,剩下的核心大概就是怎么保证库存不超卖了,也可以说要保证的是最终一致性。一般来说,针对下单和库存有两种方式:
下单即扣库存,这是最常规的大部分的做法。但是可能在活动中会碰到第二点说到的情况;
支付完成扣库存,这种设计我碰到过就是酒店行业,廉价房放出来之后被黄牛下单抢占库存导致正常用户无法下单,然后黄牛可以用稍高的价格再售卖给用户从中牟利,所以会有在一些活动的时候采取支付成功后才占用库存的做法。不过这种方式实现起来比较复杂,可能造成大量的无效订单,在秒杀的场景中不太适用。
针对秒杀建议选择下单扣库存的方式,实现相对简单而且是常规做法。
这种做法能一定程度上解决问题,但是也有可能会有其他问题。比如当大量请求落在同一条库存记录上去做 update 时,行锁导致大量的锁竞争会使得数据库的 TPS 急剧下降,性能无法满足要求。
另外一种做法就是排队,在服务层进行排队。针对同一个商品 ID 的也就是数据库是一条库存记录的做一个内存队列,串行化去扣减库存,可以一定程度上缓解数据库的并发压力。
为了保证系统的稳定性,防止你的系统被秒杀,一些质量监控就不得不做。
活动做完了,数据该怎么统计?
总的来说,面对巨量的流量我们的方式就是首先通过各种条件先筛选掉无效流量,进行流量错峰,然后再对现有的系统性能做出优化,比如页面静态化,库存商品预热,也可以通过独立部署的方式和其他的环境做隔离,最后还要解决高并发下缓存一致性、库存不能超卖的问题,防止大量的并发打爆你的数据库。
一个完整的活动从前端到后端是一个完整的链路,中间有事前的演练工作,事后的数据分析等都是必不可少的环节。
看完本文有收获?请转发分享给更多人
关注「ImportNew」,提升Java技能
好文章,我在看❤️