设计电商秒杀系统
一、背景
业务背景
公司决定进行 618 大促
1、大促的商品为各大电商平台上畅销和好评的商品
2、挑选的商品范围为 10 个品类,每个品类不超过 20 个商品
3、秒杀选择了 1000 个充电宝,10 台 iPhone 12 作为秒杀商品
4、日活大约 100w 用户
5、需要保证万无一失
6、秒杀活动为限价秒杀
技术背景
1、团队以 Java 为主
2、已经落地了微服务
3、主要渠道是自有 APP(安卓和 IOS)
4、只有下载 APP 才能参加秒杀
5、目前为单机房
目前现状
目前已经落地微服务的电商平台(类似模块 6)。目前拆分的微服务为:
用户服务
商品服务
订单服务
支付服务
购物车服务
物流服务
结算服务
统计服务
架构为:
目前的选型如下:
服务接入层:
使用 Spring Cloud Gateway 作为服务网关
使用 Hystrix 实现服务容错,以及限流、熔断等
服务运行层:
使用 Eureka 实现服务注册和服务发现
Feign 和 Ribbon 做远程服务调用和服务路由以及负载均衡
技术支撑层:
容器使用 docker
编排使用 k8s
分布式事务使用 Seate
监控工具使用 Promethus 等
基础设施层:
日志使用 ELK
分布式锁使用 redisson
消息队列使用 kafka
缓存服务使用 redis 集群
搜索服务使用 ES
监控使用 CAT
公有云服务:
阿里云 OSS
阿里云、网宿、帝联 CDN
阿里云数据分析
万网域名
DNSPOD DNS 和 HTTPDNS
约束条件
秒杀系统需要在 5 月底前完成
公司第一次大规模大促,秒杀系统不允许出现问题
秒杀系统不能影响普通商品的交易
秒杀系统人力为 10 人
只有 APP 端用户参与秒杀活动
二、业务场景
商品抢购过程如下:
商品详情数据:
1、商品名称
2、价格
3、图片信息
4、其他信息展示
结算页面数据:
1、商品名称
2、价格
3、抢购数量
4、地址
5、支付方式
6、其他信息
支付:
将生成的订单信息传给下游的订单接入接口
在秒杀的运营系统中设置好活动的开始和结束时间,以及投入的库存。在活动开始后,用户通过抢购入口,进入到活动的结算页,然后点击下单,完成商品的抢购操作。库存在抢购到的时候锁定,付款之后减去。操作过程如下:
整个下单过程:
1、生成订单
2、预占库存
3、支付
场景特点如下:
1、秒杀时候有很大的瞬时流量
2、热点数据
3、业务流程短
4、库存少
5、可能会有刷流量的情况
三、估算
用户量预估
日活 100w,按照 30%参加活动,100w*30% 有 30w 用户参加秒杀活动
关键行为
抢购:浏览商品详情页;点击抢购按钮
下单:浏览下单页面;点击下单按钮
付款:点击付款按钮
用户行为建模和行为估算
日活用户 100w,假设有 30%的用户会参与秒杀活动。充电宝 1000 个,Iphone12 10 台,一共的订单量为 1010 单。
性能估算
抢购:
抢购前用户可能会不断的刷新页面,抢购按钮变为可用后,会点击按钮,假如页面响应慢,则可能会反复点击。大部分操作集中于秒杀开始的时间点前后 10s 。
假设平均每个用户会在整个时间段内平均刷新页面 5 次,平均点击按钮 2 次。
QPS:30w*5 / 20 = 7.5w QPS
TPS: 30w*2 / 10 = 6w TPS
下单:
进入结算页面,假设秒杀的用户都提前填好地址等用户信息。只需要提交订单就可以。假设在 10s 内平均每个用户提交两次。
TPS:30w * 2 / 10 = 6w TPS
付款:
只有抢占库存才会进入到付款页面。假设 15 分钟内全部完成支付。商品一共 1010 单,这样 15 分钟内的 TPS 会比较小。
性能汇总:
QPS:13.5w QPS
TPS:6W TPS
存储估算
和之前电商系统一样静态文件使用 OSS 进行存储。因此只估算秒杀商品的存储情况。因为本次秒杀的商品信息只有两种,假定所有信息存储起来占用 10M。存储空间占用就是 10M *2 = 20M
四、总体设计
为了活动过程不影响普通商品的服务,对秒杀系统进行相应的隔离。分别从业务、系统和数据进行相应的隔离。业务上和普通商品走的流程是不一样的。针对秒杀系统涉及到的系统进行物理隔离。如下所示:
流量进行分流,从入口域名开始使用单独的域名,同时系统从流量入口开始使用单独的系统,从应用服务层到微服务进行流量隔离。在整个基础上,数据层进行单独的部署。
隔离的流程大致是,系统对秒杀 sku 进行打标,从详情页开始识别出秒杀标,路由到秒杀的商品详情页域名,进入到单独的秒杀集群。
功能结构图
系统架构图:
五、存储架构设计
目前已经实现动静分离(根据是否包含访问者个性化数据来判断),对于图片、HTML、JS、CSS 等文件存储于统一的对象存储中,实际访问的时候通过 CDN 进行访问。秒杀商品的静态页面确定好,一般不会变动。在 CDN 侧可以进行提前预热。所以下面的存储设计主要是针对动态数据的存储。
秒杀动态数据存储分析如下:
数据结构设计:
存储类型:MySQL 集群
相关数据表设计如下:
六、计算架构设计
秒杀场景下的读操作比例一定远远大于写操作比例。
负载均衡
多级负载均衡架构如下:
静态资源域名都准备两套,策略由 GSLB 进行设置,域名分别接入不同厂商的 CDN。App 在获取域名解析的时候,优先从 HTTPDNS 拿解析,如果拿不到解析或者异常由 DNS 进行保底。同一类资源客户端尝试不同的两个域名。客户端对域名采用预解析方式。
动态请求,经过 CDN 的动态加速进行。全局负载均衡策略和静态资源类似。
分布式缓存
秒杀系统系统多级缓存:
商品的图片、视频等资源缓存在 CDN 中。其余的缓存为商品详情和商品库存。商品详情这些变化比较少的数据,在秒杀活动开始之前,全量推送到所有的 web 服务器上的本地缓存上,直到活动结束,针对这类数据设置较长的定时轮询时间。对于商品库存信息设置时间短的轮询时间,对于读场景,可以接受一定程度的出现数据脏读。可能会存在已经没有库存的少量下单请求误以为有库存,等到最终扣减库存的时候,提示用户商品售罄。
热点数据
因为秒杀的缓存数据为热点数据,所以采用副本方式,结构如下:
所有副本的生成时间和实效时间添加一个随机值,避免同时生成,同时失效。
扣库存
因为减库存会产生比较大的并发更新请求直接在数据库中扣减同一秒杀商品的库存数据,这样会导致线程之间竞争 InnoDB 行锁。数据库中针对同一行数据的更改是串行执行的,如果某一个线程没有释放锁之前,其余的线程会阻塞,这样并发越高等待的线程就越多。这样的情况会影响数据库的 TPS。前面缓存了库存的数据,扣库存采用直接在库存中进行。扣减过程如下:
接口高可用
限流
在接入端采用漏桶方式进行限流。
排队
答题
七、微服务拆分
服务拆分
1、一共有 10 个后端,应用三个火枪手原则,可以同时开发 3 个微服务
2、由于是从 0 到 1 开始单独做秒杀系统,采用业务拆分方式进行
3、目前公司已经落地了电商微服务系统,有业务专家,拆分方式采用粗分然后演进的形式
最终拆分的微服务为:
秒杀详情系统
秒杀库存、商品系统
秒杀交易系统
微服务框架选型
后端团队目前技术栈统一为 JAVA,前期规模不会特别大,框架选择使用嵌入 SDK 的方式。
服务的选型和电商微服务的相同。架构类似。
八、异地多活
业务分级
秒杀按照重要性,业务分为抢购、下单、支付和页面服务
数据分类
抢购
依赖商品服务
库存数据全局唯一,需要保证数据强一致性
商品信息一般不会更改
下单
依赖订单服务
数据全局唯一,需要保证强一致性
支付
依赖支付服务
数据全局唯一,需要保证强一致性
页面服务
依赖
页面信息活动开始后一般不会更改
数据同步
缓存数据不同步,开始活动前进行预热
抢购
库存数据,数据库同步
库存缓存数据,redis cluster 同步
商品信息,redis cluster 同步
下单
数据库同步
支付
数据库同步
异常处理
抢购
CDN 直接返回 503 页面
下单
挂公告;推迟秒杀或者给予补偿
支付
挂公告;补库存或者给予优惠券
多活示意图:
九、质量设计
可测试性
服用电商微服务平台的自动化测试平台
可维护性
复用电商微服务平台的基础设施
可观测性
复用电商微服务平台的监控
项目添加基础监控
每隔一段时间进行巡检
每隔一段时间进行备份
十、演进规划
1、第一期先完成 618 功能需求
2、第二期完善秒杀系统,添加比如策略系统等,以支持更多类型的秒杀活动
评论