秒杀系统总结

欢迎大家到我的博客浏览。秒杀系统总结 | YinKai's Blog

秒杀:

做一个秒杀系统,我们需要与业务方进行沟通交流,了解清楚,才能设计出一个比较符合业务的系统,一般的流程会在后面进行一个阐述。

1、需求对齐
  • 做什么:了解什么时间,秒杀什么,数量是多少,有没有限制

    • 比如 2023年10月18日,在淘宝秒杀100台华为手机,原价15000,现价13000,一人限购一台

  • 业务流程

    • 进入商品详情页

    • 还在倒计时

    • 倒计时结束,检查是否秒杀结束。秒杀都付完款结束,就没必要继续进行

    • 检查是否名额还有剩余,没有的话, 就不能再点购买;这时候可能还会有机会,可能有人没付款或者系统原因有少卖的 名额退还,关于少卖,我们后面说原因。

    • 点购买

    • 库存抢夺,这里有许多细节,后面讨论

    • 抢到了,就创建订单

    • 在时间内支付,过时失效

    • 购买成功。

2、请求量对齐

不同的请求量的方案是完全不一样的,需要确定两个地方:

  1. 整体的流量有多大:预估业务到达时的压力

  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,失败了还有名额加载逻辑兜底。

更新中。。。

你可能感兴趣的:(秒杀系统)