欢迎大家到我的博客浏览。秒杀系统总结 | YinKai's Blog
秒杀:<!--more-->
做一个秒杀系统,我们需要与业务方进行沟通交流,了解清楚,才能设计出一个比较符合业务的系统,一般的流程会在后面进行一个阐述。
1、需求对齐
-
做什么:了解什么时间,秒杀什么,数量是多少,有没有限制
-
比如 2023年10月18日,在淘宝秒杀100台华为手机,原价15000,现价13000,一人限购一台
-
-
业务流程
-
进入商品详情页
-
还在倒计时
-
倒计时结束,检查是否秒杀结束。秒杀都付完款结束,就没必要继续进行
-
检查是否名额还有剩余,没有的话, 就不能再点购买;这时候可能还会有机会,可能有人没付款或者系统原因有少卖的 名额退还,关于少卖,我们后面说原因。
-
点购买
-
库存抢夺,这里有许多细节,后面讨论
-
抢到了,就创建订单
-
在时间内支付,过时失效
-
购买成功。
-
2、请求量对齐
不同的请求量的方案是完全不一样的,需要确定两个地方:
-
整体的流量有多大:预估业务到达时的压力
-
后端服务要支持多大的请求量:后端正常服务多少请求量,超过的就限流掉。
下面是对不同请求量的分析与方案:
-
5k:直接使用 MySQL 抗,上线前需要实际测试。
-
1w:可以考虑使用两台 MySQL。
-
10w:不能采用 20 台 MySQL,需要考虑成本。可以用一台 Reids 来搞库存,顶 10 台 MySQL,加上本身 Redis 只吃内存,不吃 CPU。
-
> 10w:Redis 集群,把库存分散到 Redis 不同分片,不同的用户走不同的分片,流量分散,分开抢名额。
3、精准度对齐
-
能否多卖:
-
什么时候会发生:在高并发下用 Redis 管理库存时,如果 Redis 重启则可能丢失已经执行的命令,库存变多;如果 Redis 是主从模式,假设发生切换,也可能丢失一部分命令,库存变多;如果查询库存和扣减库存不是原子性,在高并发下可能超卖
-
如何解决:
-
不允许发生:使用一致性更强的 MySQL 来保护,Redis 挂了再恢复可能丢失的数据,主从切换也可能会丢数据。
-
允许小概率超卖:库存走 Redis 即可,毕竟发生崩溃刚好丢数据也是小概率事件,Redis 抢到就是成功,根据抢到的结果,创建支付单即可,业务也会变得简单,Redis 名额 和 MySQL 库存的一致性就不存在了。
-
-
-
能否少卖:
-
什么时候会发生:库存扣减了,但订单没生成;订单生成了,用户没付款,回退可能失败。
-
如何解决:
-
不允许:需要一个补偿机制
-
允许发生:那就不需要补偿机制
-
-
4、难点分析
-
高并发:海量请求砸下来,可能导致服务直接挂掉,活动 G 了
-
流量削减
-
预约:预知大概的流量,与实际流量相差大概一个量级
-
验证码:拉平请求,通过验证码,将大家操作的时间由原本的一秒,拉到 1~10s 之间,相当于将请求平摊了。
-
限流:超过的流量就拒绝掉,这个是必须做的,因为不知道会由多大的流量到来,通过限流来兜底。
-
削峰:异步化削峰。
-
就是在对请求做完参数检查、频率限制之后,把后续的一整个流程进行异步化处理。可能会导致用户体验差:圈圈转很久,最后提示:商品已抢完。
-
其他方案:通常就是通过 Redia 来预扣库存,为了避免混淆,我们把 Redis 中的:成为名额、抢到名额,在绝对部分情况下都能发券成功时,再让用户等待一会是可以接收的。
-
业务逻辑:
-
校验请求
-
确认并扣减名额
-
记录扣减名额信息
-
将扣减名额成功的信息直接发给库存服务或者先丢入异步队列。
-
-
-
风控:购买资格,是否达到购买的条件;风控系统,防止恶意刷单、脚本抢购、多个账户同时抢等。
-
打击黄牛:针对某个用户接口次数过于频繁,可以只针对该用户做限制
-
针对 IP 做限制:但容易误杀,因为可能有同一个网络的用户,都是一个出口 IP。所以针对 IP 限流的阈值页不能太低,更多的还是兜底。
-
验证码:将 90% 的时间都用在验证码输入上,降低使用脚本点击的影响
-
-
限购
-
-
-
高精准
-
库存减扣
-
预扣库存:MySQL 扛不住,Redis 不够可靠,按 10w 以上流量来考虑,通过的方案就是 Redis 预扣库存操作,也就是 Redis 中存放的,可以看作名额,真正的库存不在这里。
-
MySQL 扣减:MySQL 中存放真正的库存,这里需要通过 MySQL 保证库存可靠的
-
减扣记录:MySQL 扣减成功后,就会创建订单,前端会跳到支付页,支付之后,等待支付成功。
-
-
库存补偿
-
定时任务:订单超时未支付,额度加载回 MySQL,直接加载 Redis,失败了还有名额加载逻辑兜底。
-
-