对于秒杀架构的设计,需要遵循以下个原则:
东西不能超卖、
下单成功的订单数据不能丢失、
服务器和数据库不能挂
尽量不让机器人抢走
整体的思路
秒杀架构的设计方案就是一个不断过滤请求的过程,从系统架构层面来说,秒杀系统的分层思路如下。
秒杀系统的架构设计目标就是尽可能把上层的用户请求处理掉。
下面我们通过业务的流程来设计秒杀的架构
一、浏览页面
对于PC网站,首先必选前后端分离,然后静态资源放到CDN上。例如我们平时访问的请求是
https://static.xxx.jpg。我们可以将这个staticxxx这个域名解析交给CDN服务商,因CDN服务商在全国各地都有服务器,服务器中存放着我们想要的静态资源的缓存。CDN收到这个域名后,首先会寻找一台响应最快的服务器,并指向这个服务器的IP。使用CDN好处是不浪费自己的服务器资源和带宽,且响应速度快。这样就可以把静态资源的压力拦截在系统分层的外面。
二、下单页面
1、进入下单页面
为了防止别人通过爬虫抓取页面信息,给服务器增加压力,防止恶意请求重复提交,可以做已下两层防护。
第一,页面URL后台动态获取:按照正常的活动设计流程,用户只有在秒杀活动开启后才可进入下单页,但难免有人在开启前就直接获取下单页的URL并不断刷新,这样就给后台服务器增加了压力,这个时候,我们要把下单页面URL做处理(不把它放到静态页面里,而是通过后台动态获取)。用JS判断秒杀开始时间,秒杀时间一到,就可以通过另一个请求获取URL。
第二,用户点击下单页的购买按钮后,按钮就置位disable,防止用户不断点击购买按钮。
2、订单提交
对于订单提交,我们做以下两方面设计:
第一,网关层面过滤请求,可以有以下三种方式,
(1)限定每个用户访问频率,比如每5秒下单1次。
(2)限定每个IP访问频率。
(3)把一个时间段内的请求拦截掉一个百分比,或者只允许特定数量的请求进入后台服务器(可以使用限流的漏桶或者令牌桶算法)
第二,后台服务器过滤请求,到了后台的请求,就不能是过滤请求了,而是保证秒杀商品不被超卖,以及特价商品订单数据准确。
具体实现,可以通过以下三种方式,
(1)商品库存放入缓存Redis中,如果每个请求都查询数据库库存,那数据库必然扛不住,所以我们要把库存放到缓存中,这样每次用户下单前,如果Redis的库存扣减后<0,说明秒杀失败,如果Redis库存扣减后>=0,说明秒杀成功,开始创建订单。
(2)对于生成的订单,可以写入缓存中,对于订单数据我们可以先放到缓存中,然后每隔一段时间批量插入数据库。在用户下单后,会进入一个等待页面,然后这个页面向后台定时轮询订单数据。轮询订单数据的过程中,后台先在 Redis 中查询订单数据,查不到说明已经落库,再去数据库查询订单数据,查到后直接返回给用户,用户收到消息通知后可以直接进入付款页面支付了。在数据库查询订单数据时,查不到说明秒杀失败。
(3)订单批量落库,定期将订单批量落库,且在订单落库的时扣减数据库中的库存。
三、付款页面
在付款页面,基本不需要再过滤用户请求了。在这个环节,除了保障数据的一致性,还需要注意一个要点:如果业务逻辑上出现一个订单未及时付款而被取消,记得把数据库及 Redis 的库存加回去。
为了保证秒杀系统的高可用,需要对静态资源服务器、网关、后台服务器都进行配置负载均衡,而缓存 Redis 和数据库均需要配置集群模式。
对于网关的限流 和如何应对某台服务器宕机,避免其他服务雪崩 (熔断)