毕设:设计电商秒杀系统
业务背景
商品:每个品类不超过 20 个商品,目前做了 10 个品类,挑选选品各大电商平台上畅销和好评的商品进行销售;
6.18 秒杀:本次选择了 1000 个充电宝,10 台 iPhone 12 作为秒杀商品;
日活:正常的日活大约 100 万用户;
要求:老板要求万无一失。
技术背景
团队:技术团队以 Java 为主,已经落地了微服务架构;
客户端:主要渠道是自有的 App(包括 iOS 和 Android)和微信小程序,为了促进用户转化为 App 用户,只有下载 App 才能参加秒杀活动;
机房:目前只有单机房。
一、业务页面介绍
1、详情页
包括:商品详情、秒杀按钮、秒杀地址
商品详情:将商品详情数据静态化。
秒杀按钮:秒杀未开始点击按钮无效,待秒杀开始才能点击。
秒杀地址:秒杀未开始不放入地址,待秒杀开始放入秒杀地址。
2、支付页面
商品价格、支付按钮
3、订单页
商品名称、数量、提交订单。
二、秒杀分析
1、秒杀页面
“秒杀开始前几分钟,大量用户开始进入秒杀商品详情页面,很多人开始频繁刷新秒杀商品详情页,这时秒杀商品详情页访问量会猛增”。如果请求全部打到后端服务,那后端服务的压力会非常大(后端服务要处理业务逻辑,而且还要访问数据库,吞吐量比较低)。把秒杀商品详情页做成静态页面,把商品详情、商品价格等参数、评论评价等信息全部放在这个静态页面里,然后把这个静态页面挂载到 Nginx,这样大量的商品详情页的访问请求就不用访问自己的网站(源站)。这样既可以提高访问速度,也没有给网站增加压力,同时也减少了网站带宽压力。
2、请求拦截
前端页面,相关按钮点击后置灰,防止重复提交。
网关(zuul,nginx)层,为了避免前端恶意请求,比如一些攻击脚本,在网关层要对下单等接口按 userID 限流,几秒钟只能访问一次。考虑到秒杀场景参与人多,秒杀成功的人极少,我们可以把绝大部分抢购下单请求在网关层直接拒掉,按秒杀失败处理。这样就极大减少了后端服务的压力。
3、后端压力
库存可以放到 Reids 缓存中,来提高扣减库存吞吐能力。可以利用 Redis 分片存储。
创建订单可以走异步消息队列。后端服务接到下单请求,直接放进消息队列,监听服务取出消息后,先将订单信息写入 Redis,每隔 100ms 或者积攒 100 条订单,批量写入数据库一次。前端页面下单后定时向后端拉取订单信息,获取到订单信息后跳转到支付页面。用这种批量异步写入数据库的方式大幅减少了数据库写入频次,从而明显降低了订单数据库写入压力。
二、业务量估算
日活 100w,按照 40%参加活动,100w*30% 有 40w 用户参加秒杀活动
详情页
商品详情:QPS 2000(40w/(5min*60))
库存信息:QPS 40w
秒杀:TPS 40w
订单页
地址信息:QPS 2000
商品缩略信息:QPS 2000
提交订单:TPS 2000,数据量影响可忽略不计
支付页
支付:TPS 1010,数据量影响可忽略不计
三、秒杀流程
四、架构设计
下订单扣库存主要流程
说明:
秒杀服务扣减库存不仅要在本地减库存,另外要远程统一减库存。有了远程统一减库存的操作,我们就可以根据机器负载情况,为每台机器分配一些多余的 “缓存库存” 用来防止机器中有机器宕机的情况。
我们采用 Redis 存储统一库存,因为 Redis 的性能非常高,号称单机 QPS 能抗 10W 的并发。在本地减库存以后,如果本地有订单,我们再去请求 redis 远程减库存,本地减库存和远程减库存都成功了,才返回给用户抢购成功的提示, 这样也能有效的保证订单不会超卖。当机器中有机器宕机时,因为每个机器上有预留的库存,所以宕机机器上的库存依然能够在其他机器上得到弥补,保证了不少卖。虽然 redis 内存数据库抗并发能力非常高,请求依然会走一次网络 IO, 其实秒杀过程中对 redis 的请求次数是本地库存和 缓存库存 的总量,因为当本地库存不足时,系统直接返回用户 “秒杀结束” 的信息提示,就不会再走统一扣库存的逻辑,这在一定程度上也避免了巨大的网络请求量把 redis 压跨。订单的生成是异步的, 会放到 RocketMQ 这样的即时消费队列中处理, 订单量比较少的情况下,生成订单非常快,用户几乎不用排队。
评论