Skip to main content

第7章 秒杀架构

在讲解新场景之前,先来回顾一下前面几个场景的内容:

场景解决方案
读缓存把数据存放在缓存中,减小数据库的读请求压力
写缓存碰到流量洪峰时,先将数据写入缓存中,再逐步迁移到数据库
数据收集利用消息队列把缓存中的数据迁移到数据库中

这 3 个场景中涉及的架构设计思路,本章场景都会用到。

秒杀概念

7.1 业务场景:设计秒杀架构必知必会的那些事

某一次公司策划了一场秒杀活动,该活动提供了 100件 特价商品(价格非常低),供用户于当年 10月10日22点10分0秒 开始秒杀。

  • 平台已积累了几千万用户量
  • 预计数十万用户对这些特价商品感兴趣
  • 特价商品一般会在 1~2秒 内被一抢而光
  • 秒杀开启瞬间会出现一个流量峰值

设计目标

以较小的改动来保证秒杀时的流量洪流不会冲垮服务器。

设计原则

原则说明
商品不能超卖库存100件,只能卖出100件
订单数据不能丢失下单成功的订单必须保存
服务器和数据库不能崩溃系统稳定运行
尽量别让机器人抢走商品保护普通用户权益

7.2 整体思路

秒杀架构的设计方案就是一个不断过滤请求的过程。

核心目标:尽量在上层处理用户请求,不让其往下层游动。

根据业务流程,需要在每个步骤中将请求拦截在系统上游:

浏览页面

7.2.1 浏览页面如何将请求拦截在上游

曾出现过这样的状况:系统方方面面都考虑到了,但活动一上线,第三方监控系统就显示异常——出口带宽被占满了!

用户参与活动时页面出现严重卡顿,用户抱怨不断。

解决方案:静态资源尽量使用 CDN

什么是 CDN

CDN(内容分发网络)服务商在全国各地都有服务器,服务器中存放着静态资源的缓存。

CDN 收到域名后:

  1. 寻找一台响应最快的服务器
  2. 指向这个服务器的 IP

好处

  • 不用花费自己的服务器资源和带宽
  • 响应速度快
  • 把静态资源的压力拦截在系统分层的外面

动态请求的处理

请求类型处理方式
商品详情、评论等整合成静态页面放入CDN,或放在Redis缓存
获取服务器时间放在静态资源或负载均衡层
判断秒杀结束将结束标识放在Cookie中
总结

浏览页面的用户行为,需要把请求尽量拦截在 CDN、静态资源或负载均衡侧,如果确实做不到,也要拦截在缓存中。

7.2.2 下单页面如何将请求拦截在上游

下单页面

用户进入下单页面时,主要有两个操作动作:

1. 进入下单页面

为了防止别人通过爬虫抓取下单页面信息,需要做以下防护:

防护措施说明
页面URL后台动态获取秒杀时间一到,通过另一个请求获取URL
购买按钮设为Disable用户点击后禁用,防止不断点击

2. 提交订单

秒杀系统架构方案的核心是订单提交,因为这个步骤的逻辑最复杂。

要想尽一切办法在系统各个分层中把不必要的请求过滤掉。

(1) 网关层面过滤请求

后端逻辑

如果能在网关层面拦截用户请求,性价比就很高。要是能在这一层过滤 95%以上 的请求,整个系统也将很稳定。

可以做 3 种限制:

限制类型说明
限定用户访问频率每5秒下单一次
限定IP访问频率避免机器人自动下单
时间段内拦截一定比例请求使用限流的漏桶或令牌桶算法

(2) 后台服务器过滤请求

请求进入后台服务器后,目标是:

  • 保证特价商品不超卖
  • 保证特价商品订单数据的准确性

需要考虑以下 4 点:

① 商品库存放入 Redis

用户下单前:
1. 使用 decr 操作扣减库存
2. 判断返回值
- 小于0:秒杀失败,用 incr 恢复库存
- 不小于0:秒杀成功,开始创建订单
注意

确保在秒杀期间不做上架或修改库存之类的业务操作,即通过业务流程来保证数据一致性。

② 订单写入缓存中

订单数据先不放入数据库,而是放到缓存中,然后每隔一段时间(比如100毫秒)批量插入一批订单。

用户下单后流程:

  1. 进入等待页面
  2. 页面向后台定时轮询订单数据
  3. 后台先在 Redis 中查询订单数据
  4. 查不到说明数据已落库,去数据库查询
  5. 查到后返回给用户,进入付款页面

③ 订单批量落库

定期将订单批量落库,且在订单落库时扣减数据库中的库存。

④ Redis 停止工作怎么办

场景应对措施
读Redis库存失败直接去数据库扣减库存
写订单到缓存失败直接将订单写入数据库

7.2.3 付款页面如何将请求拦截在上游

在付款页面不需要再过滤用户请求了。

要点:如果一个订单未及时付款而被取消,记得把数据库及 Redis 的库存加回去。

7.2.4 整体服务器架构

为了保障秒杀系统的高可用性,整体服务器架构中需要保证所有层级都是高可用的:

组件高可用配置
静态资源服务器负载均衡
网关负载均衡
后台服务器负载均衡
缓存 Redis集群模式
数据库集群模式
MQ主从、分片、Failover

7.3 小结

整体方案总结

秒杀系统设计 Checklist

层级检查项
CDN层静态资源是否使用CDN
静态资源层动态数据是否可以静态化
网关层是否配置用户频率限制
网关层是否配置IP频率限制
网关层是否配置限流策略
后台服务库存是否放入Redis
后台服务订单是否先写缓存
后台服务是否有Redis故障降级方案
数据层是否配置高可用

还需要注意的要点

要点相关章节
假设后台某服务因秒杀崩溃了,如何避免其他服务雪崩?第10章 熔断
网关层的限流第11章 限流
付款的数据一致性第13章 数据一致性

项目效果

这个秒杀项目上线以后,通过观察后台日志、内部监控平台的数据和第三方监控的数据,并用脚本对比库存扣减情况和订单情况,发现一切正常。

设计建议

普通客户肯定没有专门"薅羊毛"的人操作快。对于普通客户来说,随机决定比单纯比快要更有机会下单成功。所以基本上秒杀架构都会设计限流。