16 基于MQ实现秒杀订单系统的异步化架构以及精准扣减库存的技术方案

Posted 鮀城小帅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了16 基于MQ实现秒杀订单系统的异步化架构以及精准扣减库存的技术方案相关的知识,希望对你有一定的参考价值。

1.秒杀场景下的抢购流程分析

(1)商品页面问题

在秒杀活动当晚,有大量用户(可能多大几十万甚至上百万)会集中登录到APP上,然后同时访问这个秒杀活动的商品页面,这个频繁访问商品页面的问题已经被商品技术团队解决掉了

(2)订单系统与数据库压力问题

在抢购开始时,商品按钮从灰色不可用变成可点击状态。然后瞬间可能几十万甚至上百万人会同时点击这个按钮,尝试对后台发起请求去抢购这个商品。

在这个过程中,和往常购买商品一样,比如下订单、支付、扣减库存以及后续一系列事情。如果按照之前的策略,让所有请求都访问到订单系统以及订单数据库,那么不可避免的是导致订单系统和数据库压力过大。

这是亟待解决的问题。

3.用答题的方法避免作弊抢购以及延缓下单

问题:这里考虑到,有人会自己写一个抢购的脚本或者作弊软件,疯狂的发送请求去抢商品。

解决办法:在用户参与抢购前,让他点击按钮之后先进行答题,也就是先弹出来一个框,让他回答一个问题,回答正确了他才能发起抢购的请求。

这样有以下两个好处:

  1. 避免了一些作弊软件去发抢购请求
  2. 不同人的答题速度不一样,可以把答题人发送请求的时间错开,不会在一个时间点发起请求

4.独立的秒杀活动订单系统

秒杀活动的商品品类是有限的,如果让秒杀下单请求和普通下单请求都由一套订单系统来承载,那么可能会导致秒杀下单请求耗尽了订单系统的资源,或者导致系统不稳定,然后导致其他普通下单请求也出现问题,没有办法完成的下单。这里进行分流

采用对订单系统部署两个集群,一个集群是秒杀订单系统集群,一个集群是普通订单系统集群。

5.基于Redis实现下单时精准扣减库存

秒杀活动中,大量请求进入订单系统调用库存系统的接口,然后直接访问库存数据库去扣减,那么势必导致瞬时压力过大,可能让库存系统的压力很大。

解决方案,将每个秒杀商品的库存提前写入Redis中,然后当请求到来之后,就直接对Redis中的库存进行扣减。

Redis可以轻松用单机扛住每秒几万高并发。假设有一万件商品秒杀,那么前一万个请求可以成功从Redis中扣减库存,抢购到该商品。后续的请求在Redis进行扣减时发现库存已经没了,就无法抢购到商品了。

6.抢购完毕之后提前过滤无效请求

当Redis中的库存被扣减完之后,后续的请求也就不需要发送到秒杀系统中了。

这里直接可以在商品抢购完毕之后,在Zookeeper中写入一个秒杀完毕的标志位,然后ZK会反向通知nginx中我们写的Lua脚本,通过Lua脚本后续再请求过来的时候直接过滤掉,不要向后转发了。从而最大幅度削减对后端秒杀系统的请求压力。

7.瞬时高并发下单请求进入RocketMQ进行削峰

场景:一万件商品同时被一万人秒杀成功,会导致瞬间上万请求访问到订单数据库中创建订单。此时对数据库的压力就会很大。

方案:引入RocketMQ进行削峰处理。

每个请求进来在Redis中秒杀库存成功,就认为需要生成订单,此时发送一个消息到RocketMQ中去。

然后让普通订单系统从RocketMQ中消费秒杀成功的消息进行处理。对于MQ来说,这种上万的消息积压很容易就扛下来了,只要过了高峰期,订单系统很快就能消费、处理完。这个过程中不会对订单数据库造成过大的压力。

8. 秒杀架构的核心要点

  1. 在前端/客户端设置秒杀答题,错开大量人下单的时间,组织作弊器刷单
  2. 独立出来一套秒杀系统,专门负责处理秒杀请求
  3. 优先基于Redis进行高并发的库存扣减,一旦库存扣完则秒杀结束
  4. 秒杀结束之后,Nginx层过滤掉无效的请求,大幅度削减转发到后端的流量
  5. 瞬时生成的大量下单请求直接进入RocketMQ进行削峰,订单系统慢慢拉取消息完成下单操作

以上是关于16 基于MQ实现秒杀订单系统的异步化架构以及精准扣减库存的技术方案的主要内容,如果未能解决你的问题,请参考以下文章

秒杀系统后台实现详解

秒杀系统个人总结

秒杀系统实战| 如何优雅的实现订单异步处理

Redis基于(ListPubSubStream消费者组)实现消息队列,基于Stream结构实现异步秒杀下单

电商秒杀-页面静态化

基于SpringBoot+RabbitMQ+Redis开发的秒杀系统(异步下单热点数据缓存解决超卖)