1. 系统说明

1.1 概述

      秒杀:即大量用户在极短时间内同时竞争获取有限的资源。秒杀活动本身也是业务推广的重要手段。商家预设固定数量的低价或免单商品,供消费者在指定开始时间购买商品。秒杀实际是瞬时超大并发访问业务系统的场景,需要解决的问题是如何在秒杀的业务场景下保证系统的正常运行。场景的秒杀场景:

  • 春节火车票购票
  • 双十一购物节特价商品

1.2 核心问题

      秒杀最能考验系统负载能力,瞬时涌入流量是平时的十倍甚至百倍,这给系统涉及带来巨大挑战。为了秒杀的1%业务不影响99%的业务,秒杀不再是单方面或者某一模块的优化或提升,而需要进行更全面的系统设计考量。

2. 系统分析

2.1 系统难点

  • 极端时间内高并发,系统负载压力大
  • 数据库高并发读,高并发写
  • 避免影响其它业务

2.2 架构要求

  • 高可用:保证秒杀活动正常进行,设计多种保证机制
  • 一致性:保证秒杀减库存的数据一致
  • 高性能:保证系统支持高并发

2.3 面临问题

2.3.1 问题分类

  • 流量暴增,需要流量控制
  • 商品超卖,需要数据一致性保证
  • 性能优化,需要保证业务服务高可用

2.3.2 举例说明

干系人

问题分类

业务出现的问题

设计要求

用户

体验较差

秒杀开始,系统瞬间承受平时数十倍甚至上白倍的流量,直接宕机

高性能

用户

用户投诉

用户下单后无法付款,显示商品已经被购买

一致性

商家

商品超卖

100件商品,200人下单成功

一致性

商家

资金受损

恶意下单将活动商品全部下单,导致库存清零,商家无法正常售卖

高可用

商家

资金受损

黄牛通过秒杀器扫货,商家无法实现营销目的

高可用

平台

风险不可控

系统其它业务与秒杀活动不相关,变得异常缓慢,业务影响扩散

高可用

平台

拖垮网站

在线人数创新高,核心链路涉及上下游服务从前到后告警

高性能

平台

拖垮网站

数据库成为性能瓶颈,出现异常

高性能

3. 系统设计

3.1 架构原则

秒杀系统主要围绕解决“极短时间内系统高并发带来的系统负载压力,而影响正常业务的问题“。秒杀系统架构遵循一定的设计原则:

  • 尽量将请求拦截在上游
  • 充分利用缓存技术
  • 热点隔离
  • 业务隔离:比如12306的分时段售票
  • 系统隔离:软件或者硬件隔离,秒杀系统与业务系统隔离
  • 数据隔离:单独数据库,缓存集群等

3.2 架构设计

  • 互联网Web服务架构

商城秒杀系统分析与设计_商城系统

  • 秒杀系统架构样例

商城秒杀系统分析与设计_商城系统_02

  • 流量分层治理

商城秒杀系统分析与设计_商城系统_03

  • 流量控制模型

       根据上图流量分层治理模型,设计流量控制。其中CDN主要是针对静态资源分发,减少静态资源访问到到应用服务,此处不再分析。流量控制主要实现:限流,过滤流。限流是为了保证请求流量到达应用服务时,流量在应用服务负载范围内和防止恶意访问(gongji)。过滤流是在限流的基础上,过滤掉非法或者无效的请求流量。


       通常在分布式系统中,Nginx请求转发并不是直接和业务服务交互,而是通过网关服务进行。故可以再网关服务处尽早的限制和过滤掉部分流量,此处的过滤机制主要是一些通用的过滤策略。业务服务的流程过滤则是根据实际业务情况进行。


      网关和服务的限流主要针对服务间的访问,通常分布式系统中根据服务的负载情况,实时监控,动态调整实现限流。

商城秒杀系统分析与设计_秒杀系统设计_04

3.3 前端设计

3.3.1 动静分离

  • 商品列表和详情页面静态化:静态部分提前生成,可缓存,可CDN分发。

商城秒杀系统分析与设计_秒杀系统设计_05

  • 商品详情秒杀信息动态化:页面通过引用服务端动态生成的JS(不可缓存)获取商品下单信息
  • 页面校时:服务端时间
  • 用户数据:包含下单时必要的用户信息
  • 下单地址:每个商品均有独立的下单地址
  • 示例: 动态生成的商品下单信息最核心的内容是:下单地址动态,不可预先探测,防止恶意下单。
//js的地址形如: detail.js?v=1608515638999&sku=1357986420
var productDetail = {
serverTime: "2020-12-21 09:50:52",
userId: "8f4ca1df-5510-4263-8191-6af395cb547b",
address: "/order?salt=6af392ab547b"
};

     

3.3.3 前端加速

  • CDN:商品列表和详情页面采用CDN加速
  • 缓存:静态内容缓存,html页面,CSS样式,JS代码

3.3.4 流量控制

       前端的流量控制比较简单,主要目的是防止用户通过正常途径过快的创建下单请求,采用一些前端交互的方式进行流程控制。需要特别注意的是,面对专业人员这种方式实际上无法做到真正的流程控制。

  • 秒杀按钮置灰,直到秒杀开始
  • 前端用户点击秒杀按钮,点击频率限制,比如:1s内只能点击1次

3.4 站点设计

3.4.1 流量分发

  • 流量控制:流量负载均衡
  • 静态资源分发:静态资源缓存,分发

商城秒杀系统分析与设计_秒杀系统设计_06

3.4.2 流量控制

      站点层的流量控制主要是限制用户在指定时间内具有合理的HTTP请求数,该目的是为了防止系统遭受恶意访问(比如:DDoS),造成下游应用服务收到大流量的访问请求导致应用服务负载极具升高,导致应用服务瘫痪。 如下方式通过Nginx的配置实现限流

  • 限制同一IP地址并发连接( limit_req_zone )
  • 限制同一IP指定时段访问量( limit_req, 比如:每秒请求10次,QPS)

3.5 服务设计

3.5.1 业务控制

  • 下单时回答问题

根据同一终端的同一用户在指定时间内(比如:30s)访问下单超过指定次数(比如:2次),前端交互提示用户回答指定问题,答对请求继续,否则终止请求。

  • 同一用户只能购买一件商品

3.5.2 技术控制

商城秒杀系统分析与设计_商城系统_07

  • 队列,主要用于下单排队
  • 缓存,主要用于数据缓存(验证码,动态地址,用户信息)

商城秒杀系统分析与设计_商城系统_08

3.5.3 秒杀时序图

​ 秒杀系统比较独立,核心业务即:下单,支付,用户正常完成这两步,则表示秒杀成功。如下秒杀时序图主要描述下面几个流程,其中用户下单和用户订单支付是核心流程:

  • 用户秒杀下单
  •  库存不足,不能下单
  • 下单失败,秒杀失败
  • 下单成功,检查支付状态,超时未支付,秒杀失败
  • 用户支付订单
  • 下单成功,指定时间内支付成功,秒杀成功
  • 用户取消订单
  • 用户查询订单

![](./assets/秒杀系统-下单支付时序图.png)

3.5.4 下单活动图

下单活动图主要描述一次秒杀请求响应在整个秒杀系统中活动经历的步骤。重点秒杀各个环节的限流,请求过滤。


商城秒杀系统分析与设计_秒杀系统设计_09

3.6 数据库设计

3.6.1 业务隔离

      合理的秒杀架构设计理应是高并发流量经过层层过滤和流控,到达业务数据库时已经在数据库能够承载的范围内,否则将流量将击穿数据库,造成整个业务系统瘫痪。由于秒杀系统的特殊性,在数据库设计层面,通常会将秒杀系统需要的数据库和业务数据库进行隔离,保证秒杀系统不对业务系统数据库造成影响。

3.6.2 数据库表

      秒杀业务通常涉及到秒杀商品信息,秒杀商品库存这两个主要的表。秒杀系统中保证数据一致性(即:不能超卖),即秒杀商品库存。

商城秒杀系统分析与设计_商城系统_10

  • 秒杀商品信息准备阶段
  • 完成秒杀商品的信息录入工作,记录在秒杀商品信息表和秒杀商品库存信息表
  • 商品列表和详情页面静态化生成
  • 秒杀商品库存锁定阶段
  • 秒杀开始前,在业务系统数据库的商品库存信息表锁定秒杀活动需要的商品库存

3.6.2 库存更新

  • 下单锁定库存,支付更新库存
  • 分布式系统下同步更新实现方式
  • 使用redis的命令原子特性更新库存
  • 秒杀开始前,写入库存信息到redis
  • 下单锁定库存,通过Lua脚本完成redis数据更新
  • 支付更新库存,通过Lua脚本完成redis数据更新
  • 查询库存,通过Lua脚本查询redis数据
  • 定时同步redis数据到数据库
  • 数据库SQL命令更新库存
  • 乐观锁(version)
  • 悲观锁(select x for update)
  • 其它分布式锁

参考文献