Bootstrap

电商秒杀系统

1. 背景概述

1.1 业务背景

设计6.18大促秒杀系统的设计,业务模式如下:

1. 挑选各大电商平台上畅销和好评的商品进行销售,每个品类不超过20个商品,目前做了10个品类;

2. 本次6.18秒杀选择了1000个充电宝,10台 iPhone 12 作为秒杀商品;

3. 正常的日活大约100万用户;

4. 老板要求万无一失。

1.2 技术背景

1. 技术团队以 Java 为主,已经落地了微服务架构;

2. 主要渠道是自有的 App(包括 iOS 和 Android)和微信小程序,为了促进用户转化为 App 用户,只有下载 App 才能参加秒杀活动;

3. 目前只有单机房。

2. 业务场景分析

2.1 业务基本场景

1、下订单,用户购买商品,系统生成订单,这个场景并发比较大

2、扣库存,扣减库存,直到扣减为0后,不能再下单,这个场景并发比较大。

3、支付订单,用户成功下单后,支付订单,这个场景可以异步执行,并发要求没有下订单场景那么大。

登录、生成物流信息等场景可以在秒杀场景之外完成,这里不做过多描述。

2.2 业务特点

1、瞬时并发量大,秒杀时会有大量用户在同一时间进行抢购,瞬时并发访问量突增。

2、库存量少 ,秒杀活动商品库存量都很少,只有极少量用户能成功购买到商品。

3、业务简单,流程比较简单,业务场景比较少,一般都是下订单、扣库存、支付订单。

3. 架构设计

3.1 存储架构

3.1.1 存储性能估算

1、下订单

本次6.18秒杀选择了1000个充电宝,10台 iPhone 12 作为秒杀商品,故订单数量最多1010条,考虑到一定的冗余为2000条。

以后扩展到10个品类,每个品类20个商品后,订单数量应该也在10万量级上下。

2、扣库存

库存记录的数量与商品的个数相关,本次为2条,以后扩展为200条左右。

3、支付订单

支付信息,与订单信息的数量相似,本次为2000条,以后扩展为10万量级上下。

3.1.2 存储架构设计

订单、库存、支付信息都是关系型数据,所以存储使用MySQL数据库。为了保障数据的高可用,采用一主两备的方式存储,共保存3份数据。

10万订单数据、10万支付信息、200条库存信息保存在MySQL主库中。

秒杀活动主要为写入操作,不做读写分离。

3.2 计算架构

3.2.1 计算性能估算

1、下订单

正常的日活大约100万用户,假设秒杀的时候,参与用户为日活用户的3倍,为300万,这些用户提前5分钟查看秒杀商品,故商品查看的QPS为:300万/(5*60)=1万/s,考虑到系统要预留一定的性能空间,查看商品的QPS设计为2万/s 。

假设所有秒杀活动商品可以在10秒内售罄,那么生成订单的TPS为:10万/10s=1万/s,考虑到系统要预留一定的性能空间,生成订单的TPS设计为2万/s。

2、扣库存

生成订单的时候,同时要修改库存,故修改库存的TPS与生成订单相同,设计为2万/s。

3、支付订单

只有成功下单的用户才会支付,所以支付的性能要求低于生成订单,假设为生成订单的一半,故支付订单的TPS为1万/s。

3.2.2 计算架构设计--负载均衡

采用LVS、Nginx、服务网关三层负载均衡设计。

支撑TPS+QPS约7万。

3.2.3 计算架构设计--缓存

采用三级缓存架构

1、APP端设置APP缓存

2、Nginx上设置Web缓存

3、使用分布式缓存实现商品、订单、库存数据的高速读取与写入。

如果用户量、并发量增长较快,可以考虑增加CDN缓存,将商品信息中的静态内容缓存在CDN中,以便进一步降低服务器压力。

3.3 服务拆分说明

拆分为5个服务:

1、秒杀服务

缓存预热,在秒杀开始前,将商品信息和数量加载到Redis集群中。

秒杀请求响应,处理APP发起的秒杀请求,检查Redis集群中该商品的排队数量是否超过商品的总数量,如果超过,则返回商品已抢完,否则将对应商品的请求写入Redis集群的排队信息中,并发送订单创建请求报文到消息中间件中。

2、订单服务

接收订单创建请求报文,创建订单,保存在数据库中,并异步调用库存服务,扣减库存。

3、库存服务

修改对应商品的库存数量。

4、支付请求接收服务

接收APP发起的支付请求,并将支付请求报文发送到消息中间件中。

5、支付服务

接收支付请求报文,执行扣款操作,并将支付信息保存在数据库中。

3.4 总体架构设计

1、采用三层负载均衡设计,见负载均衡设计说明。

2、Redis采用集群部署,以便获得更高的写入和读取性能。

3、采用消息中间件降低流量峰值。

4、支付服务、订单服务和库存服务分别处理支付信息、订单信息和商品库存,存放在不同的数据库中。为进一步提高处理效率,支付信息和订单信息可采用分库分表设计。

3.5 其他架构设计

3.5.1 高可用架构设计

1、限流

1)请求端限流

限制请求次数,通过在APP嵌入业务逻辑,限制大部分用户流量,只准许少量用户流量进入后端服务器。

2)接入端限流

限制同一用户请求频率;随机抛弃无状态请求(抛弃浏览请求,响应下单请求)

3)微服务限流

使用写缓冲的方式,先将请求写入缓冲区,然后再进行处理。如果缓冲区慢,那么可以丢弃无法处理的请求。

2、排队

将生成订单、修改库存、支付等涉及数据库的请求放入消息队列,将同步请求,改为异步处理。

3、MySQL

MySQL采用一主两备方式,主库与备库之间采用半同步复制,并部署MHA作为主备切换工具。当主库出现异常,可以自动从主库切换到备库。

4、Redis集群

3主3从,共6个节点。

3.5.2 可扩展架构设计

拆分为5个服务,每个服务都可以单独优化与演进。

4. 总结

1、将商品信息保存在Redis缓存中,通过Redis缓存中的排队数量判断商品是否还有库存,提高系统对客户端请求的响应能力。

2、通过消息中间件、排队等方式,将同步请求转换为异步处理,降低瞬间流量对服务端造成的冲击。

3、本设计主要为秒杀系统的重点环节设计,风险控制:放盗链、判断是否为真实用户、控制同一用户下单数量等功能,本次设计中未包含。