作业十
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 存储架构设计
![](https://static001.geekbang.org/infoq/f0/f082089b15e39968bb275b826d57b8e9.png)
订单、库存、支付信息都是关系型数据,所以存储使用 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 计算架构设计--负载均衡
![](https://static001.geekbang.org/infoq/15/1572d0027f36d205137f614a700f6869.png)
采用 LVS、Nginx、服务网关三层负载均衡设计。
支撑 TPS+QPS 约 7 万。
3.2.3 计算架构设计--缓存
![](https://static001.geekbang.org/infoq/c3/c3e2dd35c1e19c5597391d77d7558a7c.png)
采用三级缓存架构
1、APP 端设置 APP 缓存
2、Nginx 上设置 Web 缓存
3、使用分布式缓存实现商品、订单、库存数据的高速读取与写入。
如果用户量、并发量增长较快,可以考虑增加 CDN 缓存,将商品信息中的静态内容缓存在 CDN 中,以便进一步降低服务器压力。
3.3 服务拆分说明
拆分为 5 个服务:
1、秒杀服务
缓存预热,在秒杀开始前,将商品信息和数量加载到 Redis 集群中。
秒杀请求响应,处理 APP 发起的秒杀请求,检查 Redis 集群中该商品的排队数量是否超过商品的总数量,如果超过,则返回商品已抢完,否则将对应商品的请求写入 Redis 集群的排队信息中,并发送订单创建请求报文到消息中间件中。
2、订单服务
接收订单创建请求报文,创建订单,保存在数据库中,并异步调用库存服务,扣减库存。
3、库存服务
修改对应商品的库存数量。
4、支付请求接收服务
接收 APP 发起的支付请求,并将支付请求报文发送到消息中间件中。
5、支付服务
接收支付请求报文,执行扣款操作,并将支付信息保存在数据库中。
3.4 总体架构设计
![](https://static001.geekbang.org/infoq/81/81b9e10eed226dfdc3ee118abf4afff9.png)
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、本设计主要为秒杀系统的重点环节设计,风险控制:放盗链、判断是否为真实用户、控制同一用户下单数量等功能,本次设计中未包含。
评论