字节跳动上亿级别秒杀系统优化,用这个方案可行吗?

秒杀相信大家都不陌生,商家会发布一些价格低廉、数量很少的商品,吸引用户抢购,例如每年双十一活动就属于典型的秒杀活动。还有类似春节12306抢票、小米手机限量发售等都可以理解为“秒杀”。

秒杀特点是持续时间短,抢购人数多,参与人数大大高于商品数量。抢购开始前后大量用户请求涌入,极易给服务造成巨大压力。如果系统设计不当,还容易造成超卖、数据丢失等问题。

本文我们主要讨论在秒杀的高并发场景下,传统订单架构存在的性能瓶颈,如何利用redis、MQ等中间件对系统做优化,解决缓存加速、防止重复提交、排队下单、超卖、少卖、削峰、异步下单等核心问题。

秒杀业务流程简介

秒杀总体业务流程可以简述为

  1. 商户创建秒杀活动,设定秒杀时间段,选择本次活动的商品,设置折扣、库存等;
  2. 用户APP端在活动即将开始时会看到秒杀活动列表,点击活动可以看到商品列表,点击商品可以查看秒杀商品详情;
  3. 商品详情页用户点击立即抢购;
  4. 如果库存充足,则创建订单成功;否则秒杀失败
  5. 提交订单后超时未支付,系统会自动关闭订单,回滚库存。

秒杀页面主要分为:

(1)首页秒杀活动列表

(2)商品详情页

普通订单系统

我们来看看普通订单系统是如何处理订单请求的.

订单下单流程图

ä¸äº¿çº§å«ç§æç³»ç»ä¼åï¼ç¨è¿ä¸ªæ¹æ¡å¯è¡åï¼ä¸äº¿çº§å«ç§æç³»ç»ä¼åï¼ç¨è¿ä¸ªæ¹æ¡å¯è¡åï¼

 

流程分析

在springcloud环境下,普通订单下单流程可以总结为:

1.用户确认订单、提交订单,发送下单请求至订单微服务;

2.订单服务会调用用户服务做一系列业务校验,如账号是否异常等;

还会调用商品服务,校验商品信息;

商品服务又会调用活动服务,校验优惠券、计算优惠等;

3.各服务从MySql获取业务数据,进行业务计算、业务校验;

4.生成订单,最后将订单数据入库。

瓶颈分析

普通订单系统分析

​ 以上是传统微服务架构订单业务的经典流程,在用户量不多、并发不高的正常业务场景下,支撑起正常的业务需求是没问题的。可以通过部署集群、数据库分库分表和读写分离、sql调优、硬件升级等方式,进一步提高系统稳定性和抗并发能力。

但是对于秒杀业务场景,由于秒杀活动特点是商品库存少,参与人数多,在秒杀开始前后,系统的瞬间请求流量飙升,对后端服务尤其是数据库造成很大压力,如果不能进行有效削峰、限流,所有请求一次性到某一台服务器或数据库上,服务很有可能出现卡顿、不可用甚至宕机的可能,给用户造成不良体验。

普通订单系统处理秒杀业务的瓶颈

数据库负担过重

从上图可以看出,仅一个下单请求,所有服务的查询、修改等都是直接操作mysql,没有用到缓存,秒杀开始,系统瞬间承受平时数十倍甚至上百倍的流量,导致mysql cpu占用升高,压力过重,直接拖慢所有系统服务。

频繁的跨服务调用

由上图可以看出,秒杀相关接口在查询业务数据时,由于下单业务复杂,需要校验的业务项非常多,后端不得不频繁跨服务调用,订单服务会调用商品、用户等服务、活动等服务,活动服务可能还会调用其它服务,

调用链过多、过长,可能某一环节响应时间过长而拖慢系统整体速度,同时微服务之间的互相调用也会占用系统CPU、内存资源,造成服务器性能下降。

容易产生大量无效下单请求

秒杀商品只有10个,却有1000个下单请求,这1000个请求到后端会全部走一遍下单逻辑,而实际上真正成功的订单只有10个,其它秒杀失败的请求没有过滤掉。

没有排队处理请求

所有请求一窝蜂涌入,容易造成请求积压,造成OOM。

串行处理

在高并发情况下,为保证不出现超卖问题,所有涉及库存操作都会加锁处理,串行执行,增加请求处理耗时。即使系统能容忍很高的并发,也很可能出现请求堆积、超时等情况。

链接暴露

秒杀url很容易通过抓包工具获取,竞争对手或黄牛党可以通过脚本或刷单工具发送下单请求,轻则活动还没开始商品便卖光,严重的服务器宕机,活动失败,GG。

秒杀常见优化方案

关于秒杀系统,可优化的点非常多,这里列出如下几点:

前端层面

前端优化(前端按钮点击频率限制、限制用户维度访问频率、限制商品维度访问频率、验证码机制等)

页面数据的静态化+多级缓存(CDN加速+Nginx+Redis)

服务层面

web服务器优化(tomcat、undertow)

nginx限流

负载均衡

服务器硬件升级

削峰处理

服务降级、熔断

jvm性能调优

业务层面

数据库分库分表、读写分离

sql调优

代码调优

.................

本次优化关键点

​ 实际上,受限于经费、时间、团队技术水平等条件,实际优化中我们可能无法对以上几点逐条优化,一是耗时耗力,二是可能没必要,具体优化时还是要以实际业务并发量为准。 在资源、时间有限的情况下,我们需要一个高效、最能够显著提升效果的优化方案。

本文主要介绍在服务层面,如何针对瞬时的高并发请求做削峰处理;业务层面,如何利用缓存减轻mysql数据库访问压力、如何排队处理、如何防止重复提交、防止超卖问题等。

利用缓存

秒杀的业务特点是读多写少,一个秒杀商品只有10个,可能有10w个人来抢,最终只有10个用户会产生写操作,其它请求都是查询库存,非常适合利用缓存优化。

缓存这块我们选用redis,redis基于内存,内存的读写速度非常快;同时redis内部是单线程操作,省去了很多上下文切换线程的时间。redis采用多路复用技术,非阻塞式IO,可以抗住高达百万级的并发量。

排队下单

利用redis进行排队抢单,记录排队数据。秒杀请求到后端后,不立即走创建订单逻辑,先通过redis校验排队、库存信息,校验通过后将秒杀请求缓存到redis。

削峰处理

通过RabbitMQ消息队列削峰:

秒杀请求不直接生成订单,先存入MQ消息队列,可以写一个消息监听器,平缓消费秒杀请求数据,减轻数据库并发量。

优化方案设计

数据缓存

通过以上分析我们知道秒杀的最大瓶颈便是mysql,所以我们要将mysql的压力转移给缓存。

在活动开始前,我们可以配置循环定时任务,将秒杀活动、秒杀商品相关信息全部缓存到redis中,可以根据活动信息,设置缓存的失效时间。

前端秒杀活动、商品详情等数据的获取,全部走redis。

ä¸äº¿çº§å«ç§æç³»ç»ä¼åï¼ç¨è¿ä¸ªæ¹æ¡å¯è¡åï¼

 

确认订单

用户发送确认订单请求时,首先校验该用户是否是否已经排队,排队信息从redis中获取,如果已经排队下单,直接返回; 否则继续走确

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值