缓存综合项目--秒杀架构

123 阅读6分钟

我正在参加「掘金·启航计划」

前面几篇文章我们学习了读缓存、写缓存和数据收集的场景,在这篇文章中我们将综合这三个方面来实现一个秒杀架构。 秒杀架构的特点是 僧多粥少,一般来说商品会在两秒内被抢光,后续进来的用户只能看到秒杀结束的界面,因此秒杀开始的前两秒中会出现一个流量峰值。并且秒杀架构设计时要保证商品不能被超卖、下单数据不能丢失、服务器与数据库不能崩溃、尽最大可能屏蔽机器人抢走商品。下面针对这四个方面我们来讲解一下。

一、实现思路

1.1 架构简述

秒杀架构就是一个不断过滤请求的过程,一般来说秒杀系统分为5层:静态资源/负载均衡网关后台服务器缓存数据库。我们尽量会在第一层和第二层对用户请求进行处理,关于怎么将请求拦截在第一层和第二层的问题,需要结合实际业务来考虑。

1.2 思路

秒杀系统的业务流程分为四层:展示页面下单付款结果。下面就针业务流程的四层分别来讲解一下实现思路。

1.2.1 展示页面拦截请求

对于商品展示页面,我们大部分情况会使用到内容分发网络,也就是常说的CDN,使用CDN的优点是我们不需要花费自己的服务器资源,并且响应速度快,可以把静态资源的压力转嫁到外部系统。 既然有静态资源,那必定也有动态资源。动态资源我们无法使用CDN进行专家压力。例如针对评论、商品详情的请求,一般情况下我们都是利用前端技术从后台服务中获取到的,针对这种动态的数据,我们可以把它们作为静态数据存放到CDN中,因为这种数据在秒杀期间变化的可能性很小。接着就是设置秒杀按钮的开启状态,这里我们千万要注意,一定不要获取客户端的本地时间,应该获取服务器的时间,当获取的服务器时间等于或大于秒杀开启时间是将秒杀按钮设置为可用即可。每个客户端都会发送获取服务器时间的请求,为了减轻服务器压力,我们可以把这个请求放在静态资源中或者负载均衡里,这样用户的请求就不会进入到后续的服务中。关于如何判断秒杀结束的问题,做法是将秒杀结束的标志放在 Cookie 中,如果客户端不存在结束标识就让请求进入到后台服务器,后台服务器收到请求后如果发现内存中页不存在结束标识,就让请求进入到缓存中,如果缓存中也没有结束标识,就代表当前秒杀活动并没有结束。

1.2.2 下单拦截请求

在下单时用户会执行两个动作,一个是进入下单页面,一个是提交订单。下面我们就针对这两个动作来说一下。

1.2.2.1 进入下单页面

在进入下单页面前,我们需要做两个防护:

  1. 页面URL地址从后台动态获取,当秒杀时间一到,就可以利用前端技术向服务端获取下单页面的URL,这样可以防止别人提前侦知下单页面的地址或者下单页面的地址拼接规则,从而利用机器人进行不断的提交恶意请求。
  2. 当用户提交订单后,提交按钮变为不可用状态,防止用户不断的点击。
1.2.2.2 提交订单

在提交订单方面,我们可以在系统的不同分层中过滤掉一些不必要的请求。

  1. 网关 在网关层面过滤请求是一个性价比相对较高的方案。我们可以限制每个用户的访问频率、限制每个IP的访问频率、随机过滤掉一定时间内的一定比例的请求,甚至我们可以只让特定数量的请求进入(具体做法将会在后面文章讲解)。
  2. 后台服务器 经过网关的过滤,进入到后台服务器的请求已经减少了很多,现在我们就要探讨如何保证商品部超卖和订单数据的准确性。这要从四个方面考虑:
  • 商品库存放入缓存(Redis、MongDB等) 如果每个请求都向数据库查询商品库存的话,数据库将无法承受,因此需要把库存数据放入缓存中,每次下单前对库存执行减1操作,如果结果小于零,就代表没库存了,并将库存数据恢复到0,如果结果大于零就表示秒杀成功,之后开始创建订单。

TIP:如果在秒杀阶段,有别的服务或别的代码修改了数据库的库存,就会出现问题,那么我们应该做的是确保商品在秒杀期间其他服务和其他代码修改库存。

  • 订单写入缓存 前面的文章我们讲过写缓存的方案,将订单数据放入缓存中,然后每隔一段时间就批量插入一次订单,用户下单后首先进入等待页面,等待页面定时轮询订单数据,如果在缓存中没查到订单就说明订单已经落库了,然后再去查询数据库,如果查到了订单数据,就将信息返回给等待页面,并跳转到支付页面。
  • 订单批量落库 这里需要注意,在订单批量落库后要相应的减去数据库中的库存数量。
  • 缓存宕机处理发放时 如果在读库存信息的时候缓存宕机了,就需要直接从数据库中去扣减库存,执行的逻辑和在缓存中执行库存扣减的逻辑相同。如果在写入订单的时候缓存粗线宕机,那就将数据直接存入数据库。
1.2.3 付款拦截

在付款页面我们不需要考虑拦截请求,我们只需要保证数据一致性即可,同样还要处理如果一个订单支付超时而被取消或者用户主动取消的情况,那么这时就需要将Redis的库存和数据库的库存数据加回去。

二、总结

到这里,秒杀架构的知识基本上就讲完了。在整个秒杀架构中,我们要保证系统的5层都是高可用的, 静态资源服务器、网关和后台服务器需要配置负载均衡,缓存和数据库需要配置为集群。当然,有些秒杀架构中会加入MQ,一般需要用在服务间触发通知的场景,也需要保证高可用。