毕业设计 - 电商秒杀系统
背景介绍
【业务背景】
你作为一个电商创业公司的架构师,负责设计 6.18 大促秒杀系统的设计,你们的业务模式如下:
1. 你们挑选选品各大电商平台上畅销和好评的商品进行销售,每个品类不超过 20 个商品,目前做了 10 个品类;
2. 本次 6.18 秒杀选择了 1000 个充电宝,10 台 iPhone 12 作为秒杀商品;
3. 正常的日活大约 100 万用户;
4. 老板要求万无一失。
【技术背景】
1. 技术团队以 Java 为主,已经落地了微服务架构;
2. 主要渠道是自有的 App(包括 iOS 和 Android)和微信小程序,为了促进用户转化为 App 用户,只有下载 App 才能参加秒杀活动;
3. 目前只有单机房。
业务场景分析
电商业务场景
商品展示与推荐:电商平台会展示商品,包括图片、描述、价格等信息。此外,通过数据分析和推荐算法,为用户提供个性化的商品推荐。
用户注册与登录:用户需要注册并登录电商平台,以便购物、查看购物车、查询订单等。
商品搜索与筛选:用户可以通过关键词搜索商品,或使用分类、筛选条件等方式找到心仪的商品。
结算与下单:用户在购物车中选择需要购买的商品,填写收货地址、选择支付方式等信息,确认订单信息后下单。
支付:用户根据订单信息,通过在线支付方式(如支付宝、微信支付、银行卡等)支付订单款项。
订单处理:电商平台接收到订单后,进行订单处理,包括库存检查、订单分配等。
秒杀业务
秒杀大致流程
关键点
用户必须在 App 上才能完成秒杀活动,包括 IOS 和 Android 应用、以及小程序等。
因为电商业务本身已经做了微服务架构,为保证秒杀活动的顺利进行,同时不会冲击到正常的电商业务活动,考虑将秒杀活动单独做一个微服务,在业务上同正常的商品售卖进行隔离,同时后续的秒杀活动也能在此系统上进行。
秒杀活动的特点,就是将用户全部集中到同一个时刻,然后一起开抢某个热门商品,而热门商品的库存往往又非常少,所以持续的时间也比较短,快的话可能一两秒内就结束了。在此期间我们要对库存做针对性的设计,保证活动的准确性,确保商品不会超卖。
除了保证准确性以外,稳定也非常重要;为此,我们要通过流控、削峰、限流、降级、热点和容灾等手段保证秒杀系统的高可用性。
在保证了准确性和高可用的基础上,我们应该尽量实现高性能、低延迟,让秒杀活动响应更快,从而提高用户的体验性。
总体架构思路
框架规模
老用户
假设电商平台的平时活跃用户比例为 20%,则可估计总的用户数为: 100 万 (日活) / 20% (活跃度) = 500 万(总用户);假设有一半用户参与秒杀活动,则秒杀用户数为:500 万(总用户) * 50%(参与用户比例) = 250 万(参与用户数);
新用户
考虑到 iphone12 有较高的吸引力,同时充电宝又较为刚需,可假设该促销活动拉新的比例为 10%,即 500 万(总用户)* 10% (拉新比例)= 50 万 (新用户注册)。
总用户数
秒杀用户数:老用户数 (250 万)+ 新用户数(50 万)= 300 万。所以考虑按照百万用户规模架构进行框架设计。
技术点实现
存储:MySQL 分库分表策略,将订单数据、用户数据、商品数据等存储在不同的数据库和表中
缓存:CDN 缓存热点数据、Redis 作为缓存存储,减轻数据库压力,提高系统性能。
负载均衡:Nginx 作为负载均衡器,将流量分发到不同的应用服务器上,同时采用 IP Hash 算法进行负载均衡,保证同一个用户的请求始终分发到同一台服务器上,避免 session 不一致问题。
高可用:MySQL 主从复制,Redis 主从复制,应用服务集群部署,秒杀活动中,保证数据和服务的高可用性是至关重要的。
可扩展:采用微服务架构,可以应对秒杀活动中的流量波动,提高系统的可扩展性
限流:采用令牌桶算法限制用户请求速率,避免系统过载
?降级:优先保证下单、结算任务,其次为登录业务,注册业务放到最后
存储架构设计
考虑到秒杀商品较少,不需要单独新建数据库,只需要将秒杀的商品进行标记即可,此处分析该电商系统的存储架构设计。
存储性能估算
注册
新用户加老用户总数为 550 万,考虑冗余,假设有 600 万用户注册信息。
电商业务的个人信息一般包括用户基本信息(包含头像)、账号信息、收货地址信息:
用户基本信息:包括姓名、性别、年龄、联系方式、头像图片等。
每个字段占用的字节数不同,假设姓名一般占用 2~30 字节不等,性别和年龄可以用 1~2 字节存储,联系 方式可以用 10~20 字节存储,假设每个字段平均占用 10 字节,则用户基本信息大约需要占用 40 字节。
账号信息:包括用户名、密码、邮箱地址、手机号码等。
用户名、密码、邮箱地址和手机号码等字段的存储方式不同,用户名和密码可以用 20~30 字节存储,邮箱地址可以用 30~50 字节存储,手机号码可以用 10~20 字节存储,假设每个字段平均占用 30 字节,则账号信息大约需要占用 120 字节。
收货地址信息:包括收货人姓名、手机号码、详细地址等。
收货地址信息:收货人姓名和详细地址等字段的存储方式不同,假设收货人姓名可以用 2~30 字节存储,详细地址可以用 50~100 字节存储,假设每个字段平均占用 30 字节,则收货地址信息大约需要占用 60 字节。
头像:头像为图片,此处按 1M 字节来考虑。
个人信息存储量为:600 万 * 220 字节(单人信息文字存储量) ≈ 1.5GB
图片数据:600 万 * 1M 字节 ≈ 6TB
随着新用户的增长,存储量还会持续增加。
个人信息存储量较少,而且极少变更,考虑使用 Mysql 主备复制架构,进行存储。
图片数据存储量较大,只是单纯的文件存储,不包含关系信息,考虑使用 Hbase 集群架构,进行存储。
登录
秒杀日活为 250 万,加上又新注册的用户 50 万,总计有 300 万的登录请求。
登录记录,数据存储量较大,同样不包含关系信息,而且较其他数据也较为隔离,所以考虑使用 Hbase 集群架构进行存储,会更有效率。
商品详情
10 个种类,每个种类 20 个商品,总商品数量为:10 * 20 = 200 个商品,考虑预留量为 2 倍,总计有 200 * 2 = 400 个商品量。
商品详情页包括文字和图片,假设:
文字内容:假设商品详情页包括商品标题、描述、规格等文本信息,总共约 1000 个字。一个汉字在 UTF-8 编码中占 3 个字节,所以总共约为 3000 字节。
图片内容:商品详情页通常包括多张图片,如商品主图、细节图、使用场景图等。假设平均每张图片大小为 1MB,共有 10 张图片,那么图片内容的总字节数约为 1MB * 10 = 10M。
那么每个商品详情页的文字存储量为:400 * 3000 字节 ≈ 1.2MB。
图片存储量为:400 * 10MB ≈ 4GB,考虑冗余,则图片总存储量为:5GB。
因为商品信息是供百万用户去读的,而且用户浏览的商品信息是一样的,考虑到 Redis sentinel 支持主从,从机可以分担一部分读取的压力,所以商品信息使用 Redis sentinel 集群架构进行存储,从而可以实现较高的性能。
订单
日活有百万,假设每两个用户有一个产生购买行为,同时假设订单信息量(不考虑图片)为 10KB,每天订单量 50 万 * 10KB ≈ 5GB。
订单中的图片信息可从商品信息中获取。
因为订单量每天都会累加,同时电商后台会对订单进行分析,优化电商系统,所以考虑使用 Mysql 分库分表对订单进行存储
存储架构设计
对上述场景中的存储架构进行合并,得到:
MySQL 的主备复制和分库分表统一为 MySQL 集群
计算架构设计
性能估算
注册
考虑到有 50 万新用户注册,假设注册动作分布在白天的 8 小时内,则注册的 TPS 为:50 万 / (8 * 3600) ≈ 18 / s,TPS 较小,可以忽略。
登录
秒杀日活为 250 万,加上有新注册的用户 50 万,总计有 300 万的登录请求。假设登录请求集中在秒杀前的 1 个小时,则登录的 TPS 为:300 万 / (1 * 3600) ≈ 1000 / s。
商品详情
用户在进行商品秒杀的时候,会有频繁刷新商品详情页的操作,此处假设有 20%的用户在秒杀前的半分钟内平均刷新 5 次,则查询详情页的 QPS 为:300 万 * 20% * 5(次)/ (30)= 10 万 / s, 考虑 50%的预留量,则查询商品的 QPS 为: 15 万 / s。
抢购
在秒杀的过程中,系统一般会先查一下库存是否足够,如果足够才允许下单,写数据库。如果不够,则直接返回该商品已经抢完。由于大量用户抢少量商品,只有极少部分用户能够抢成功,所以绝大部分用户在秒杀时,库存其实是不足的,系统会直接返回该商品已经抢完。
此功能也是系统中并发量最大的操作,所有秒杀用户可能集中在几秒中内,发出抢购请求,如果此时所有请求(几百万)都直接访问数据库或缓存,会给数据库或缓冲带来极大的压力和挑战,所以考虑采用削峰和限流的方式对流量进行筛选。
假设通过削峰和限流之后,流量剩余 20%,同时,点击抢购动作在 2 秒内完成,则查询库存的 QPS 为:300 万 * 20% / 2 = 30 万 / s。
下单
秒杀商品有 1000 个充电宝,10 台 iPhone 12 ,共计 1010 件商品,所以真正能形成有效订单量为 1010。
考虑下单成功的客户不一定在有效期内支付,或者其他原因,导致订单取消等问题,此处考虑 2 倍冗余,即 2000 订单量,假设所有商品在 1s 内抢完,则下单的 TPS 为:2000 / 1 = 2000 / s。
支付
只有下单成功后才会进行付款,同时,支付主要依赖于第三方支付平台,此处不进行考虑
负载均衡
性能量级的大头为浏览商品和抢购,考虑到浏览商品和抢购的性能量级均已达到 10 万量级,尤其抢购的量级已经达到 30 万,所以负载均衡决定采用 LVS,LVS 的性能量级为:10 万~100 万。
单机房内负载均衡架构为:
缓存架构
由于是创业型公司,不考虑使用 CDN,成本太高。
同时由于应用内缓存实现起来复杂度较高,比如要保证应用内缓存和分布式缓存的一致性,也要考虑应用内缓存之间的一致性,实现和维护的复杂度对于创业公司来说太高,所以不考虑使用应用内缓存。
使用 3 级缓存架构:
说明:
秒杀商品的文本和图片信息可以在活动前下发到 App 缓存。
WEB 容器缓存主要是在 Apache、Tomcat、Nginx 等容器进行缓存,主要存储静态资源。
商品信息、库存信息、订单信息等,放到 Redis 缓存中。
可扩展架构
微服务拆分思路:
按性能拆分:将访问量比较大的业务拆分出来,商品服务。
按重要程度拆分:将重要程度高的业务拆分出来,订单服务和库存服务。
用户服务(会员服务)单独拆分成一个会员服务。
其他服务汇总成综合服务
考虑到支付服务调用第三方支付系统,此处不再单独拆分。
微服务拆分:
高可用架构
由于只有单机房,可用性取决该机房的稳定性,只能做到同城单中心,后续随着业务量的增长、营收的增长为了保证业务的高可用和稳定性,可以采用同城多机房,或异地多活的高可用架构。
补充
关于限流
采用令牌桶算法限制用户请求速率,避免系统过载为不同类型的请求设置不同的限流阈值,确保关键请求的优先处理原因:限流可以保证系统的稳定运行,避免因流量过大导致的服务崩溃。
演化
由于业务背景和技术背景的限制,目前尚未考虑实施这些设计点。在未来业务发展和技术演进的过程中,可根据需要进行相应的优化和改进,可以考虑以下优化建议:
引入 CDN,加速静态资源的加载速度,提高用户体验
部署多机房,提高系统的容灾能力
采用分布式锁,保证分布式环境下的数据一致性
版权声明: 本文为 InfoQ 作者【源】的原创文章。
原文链接:【http://xie.infoq.cn/article/6636d597b93a2682e52957963】。文章转载请联系作者。
评论