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章 数据一致性

项目效果​

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

设计建议

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