高频面试题:秒杀场景设计
秒杀这个话题到现在来说已经是一个老生常谈的话题了,不过因为又临近一年一度的双11,而且发现前段时间无论是阿里还是腾讯一些大厂其实还是在频繁的问到这个场景题,所以还是准备拿出来说说。
秒杀从规模上来说可以分为大秒和小秒。大秒指的是比如双11这种特定的节日,商品规模超大、价格超低、流量超大的这种类型活动,小秒一般指的是商家自己配置的一些时段类型的活动,由商家自己指定时间上架。从形式来说还可以分为单时段秒杀和多时段秒杀。但是在这个场景里,我们一般就是指的单时段大型秒杀。
秒杀设计要面对的压力和难度有几点:
-
怎么保证超高的流量和并发下系统的稳定性?如果峰值的QPS达到几十万,面对巨大的流量的压力系统怎么设计保证不被打崩?
-
怎么保证数据最终一致性?比如库存不能超卖,超卖了那亏本的要么就是商家要么就是平台,用户反正不背这个锅,超卖了就今年325预订。
当然,涉及到这种大型的活动,还需要考虑到数据统计分析,总不能活动做完了,效果不知道怎么样。
系统架构
假设今年的双11预估峰值QPS将会有50万(我随便扯的),而根据我们平时的经验单机8C8G的机器可以达到1000左右的QPS,那么从理论上来说我们只要500台机器就可以抗住了,就有钱任性不行?这么设计的话只能出门右转不送了。
流量过滤
本质上,参与秒杀的用户很多,但是商品的数量是有限的,真正能抢到的用户并不多,那么第一步就是要过滤掉大部分无效的流量。
-
活动开始前前端页面的Button置灰,防止活动未开始无效的点击产生流量 -
前端添加验证码或者答题,防止瞬间产生超高的流量,可以很好的起到错峰的效果,现在的验证码花样繁多,题库有的还要做个小学题,而且题库更新频繁,想暴力破解怕是很难。当然我知道的还有一种人工打码的方式,不过这个也是需要时间的,不像机器无限刷你的接口。 -
活动校验,既然是活动,那么活动的参与用户,参加条件,用户白名单之类的要首先做一层校验拦截,还有其他的比如用户终端、IP地址、参与活动次数、黑名单用户的校验。比如活动主要针对APP端的用户校验,那么根据参数其他端的用户将被拦截,针对IP、mac地址、设备ID和用户ID可以对用户参与活动的次数做校验,黑名单根据平时的活动经验拦截掉一部分羊毛党等异常用户。 -
非法请求拦截,做了以上拦截如果还有用户能绕过限制,那不得不说太牛X了。比如双11零点开始还做了答题限制,那么正常人怎么也需要1秒的时间来答题吧,就算单身30年手速我想也不能超过0.5秒了,那么针对刚好0点或者在0.5秒以内的请求就可以完全拦截掉。 -
限流,假设秒杀10000件商品,我们有10台服务器,单机的QPS在1000,那么理论上1秒就可以抢完,针对微服务就可以做限流配置,避免后续无效的流量打到数据库造成不必要的压力。针对限流还有另外一种栅栏方式限流,这是一种纯靠运气的限流方式,就是在系统约定的请求开始的时间内随机偏移一段时间,针对每个请求的偏移量不同,如果在偏移时间之内就会被拦截,反之通过。
性能优化
做完无效流量的过滤,那么可能你的无效请求已经过滤掉了90%,剩下的有效流量会大大的降低系统的压力。之后就是需要针对系统的性能做出优化了。
-
页面静态化,参与秒杀活动的商品一般都是已知的,可以针对活动页面做静态化处理,缓存到CDN。假设我们一个页面300K大小,1千万用户的流量是多少?这些请求要请求后端服务器、数据库,压力可想而知,缓存到CDN用户请求不经过服务器,大大减小了服务器的压力。 -
活动预热,针对活动的活动库存可以独立出来,不和普通的商品库存共享服务,活动库存活动开始前提前加载到redis,查询全部走缓存,最后扣减库存再视情况而定。 -
独立部署,资源充足的情况下可以考虑针对秒杀活动单独部署一套环境,这套环境中可以剥离一些可能无用的逻辑,比如不用考虑使用优惠券、红包、下单后赠送积分的一些场景,或者这些场景可以活动结束后异步的统一发放。这只是一个举例,实际上单独针对秒杀活动的话你肯定有很多无用的业务代码是可以剥离的,这样可以提高不少性能。
经过这两步之后,最终我们的流量应该是呈漏斗状。
超卖
秒杀除开高并发高流量下的服务稳定性之外,剩下的核心大概就是怎么保证库存不超卖了,也可以说要保证的是最终一致性。一般来说,针对下单和库存有两种方式:
-
下单即扣库存,这是最常规的大部分的做法。但是可能在活动中会碰到第二点说到的情况。
-
支付完成扣库存,这种设计我碰到过就是酒店行业,廉价房放出来之后被黄牛下单抢占库存导致正常用户无法下单,然后黄牛可以用稍高的价格再售卖给用户从中牟利,所以会有在一些活动的时候采取支付成功后才占用库存的做法。不过这种方式实现起来比较复杂,可能造成大量的无效订单,在秒杀的场景中不太适用。
针对秒杀建议选择下单扣库存的方式,实现相对简单而且是常规做法。
方案
-
首先查询redis缓存库存是否充足 -
先扣库存再落订单数据,可以防止订单生成了没有库存的超卖问题 -
扣库存的时候先扣数据库库存,再扣减redis库存,保证在同一个事务里,无论两者哪一个发生了异常都会回滚。有一个问题是可能redis扣成功了由于网络问题返回失败,事务回滚,导致数据库和缓存不一致,这样实际少卖了,可以放到下轮秒杀去。
这种做法能一定程度上解决问题,但是也有可能会有其他问题。比如当大量请求落在同一条库存记录上去做update时,行锁导致大量的锁竞争会使得数据库的tps急剧下降,性能无法满足要求。
另外一种做法就是排队,在服务层进行排队,针对同一个商品ID的也就是数据库是一条库存记录的做一个内存队列,串行化去扣减库存,可以一定程度上缓解数据库的并发压力。
质量保障
为了保证系统的稳定性,防止你的系统被秒杀,一些质量监控就不得不做。
-
熔断限流降级,老生常谈,根据压测情况进行限流,可以使用sentinel或者hystrix。另外前端后端都该有降级开关。 -
监控,该上的都上,QPS监控、容器监控、CPU、缓存、IO监控等等。 -
演练,大型秒杀事前演练少不了,不能冒冒失失的就上了吧。 -
核对、预案,事后库存订单 金额、数量核对,是否发生超卖了?金额是否正常?都是必须的。预案可以在紧急情况下进行降级。
数据统计
活动做完了,数据该怎么统计?
-
前端埋点 -
数据大盘,通过后台服务的打点配合监控系统可以通过大盘直观的看到一些活动的监控和数据 -
离线数据分析,事后活动的数据可以同步到离线数仓做进一步的分析统计
总结
总的来说,面对巨量的流量我们的方式就是首先通过各种条件先筛选掉无效流量,进行流量错峰,然后再对现有的系统性能做出优化,比如页面静态化,库存商品预热,也可以通过独立部署的方式和其他的环境做隔离,最后还要解决高并发下缓存一致性、库存不能超卖的问题,防止大量的并发打爆你的数据库。
一个完整的活动从前端到后端是一个完整的链路,中间有事前的演练工作,事后的数据分析等都是必不可少的环节。
- END -往期推荐
点击二维码识别关注
点在看,让更多看见。
本文分享自微信公众号 - 科技缪缪(kejimiumiu)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
第九篇|Spark的五种JOIN策略解析
JOIN操作是非常常见的数据处理操作,Spark作为一个统一的大数据处理引擎,提供了非常丰富的JOIN场景。本文分享将介绍Spark所提供的5种JOIN策略,希望对你有所帮助。本文主要包括以下内容: 影响JOIN操作的因素 Spark中JOIN执行的5种策略 Spark是如何选择JOIN策略的 影响JOIN操作的因素 数据集的大小 参与JOIN的数据集的大小会直接影响Join操作的执行效率。同样,也会影响JOIN机制的选择和JOIN的执行效率。 JOIN的条件 JOIN的条件会涉及字段之间的逻辑比较。根据JOIN的条件,JOIN可分为两大类:等值连接和非等值连接。等值连接会涉及一个或多个需要同时满足的相等条件。在两个输入数据集的属性之间应用每个等值条件。当使用其他运算符(运算连接符不为=)时,称之为非等值连接。 JOIN的类型 在输入数据集的记录之间应用连接条件之后,JOIN类型会影响JOIN操作的结果。主要有以下几种JOIN类型: 内连接( Inner Join):仅从输入数据集中输出匹配连接条件的记录。 外连接( Outer Join):又分为左外连接、右外链接和全外连接。 半连接...
- 下一篇
如何利用设计模式改善业务代码?
在业务部门的开发中,大多数的我们在完成的业务的各种需求和提供解决方案,很多场景下的我们通过 CRUD 就能解决问题,但是这样的工作对技术人的提升并不多,如何让自己从业务中解脱出来找到写代码的乐趣呢,我做过一些尝试,使用设计模式改善自己的业务代码就是其中的一种。让代码变得更加简洁和提升健壮性,从代码中寻找一些欢乐。 前言 阿里优秀的人很多,他们身上都有着共同的特质,就是看问题的思考能力,让我最佩服的是思考力强的人,对事情有深入见解和观点的人,大多数人还是停留在表面看问题,很多禁锢在思想里逃不出来,古人说,立德立言立功为三不朽,立言就是思考力和认知力,人和人的差异,在长久的职场中或者生活中,除去运气外,其实就是认知和思考力的差异。所以除去繁琐的工作后,如何在有限的时间从代码中寻找欢乐,需要提高的是思考和规划能力。 责任链设计模式 ▐模式定义 责任链模式(Chain of Responsibility Pattern), 是行为型设计模式之一。这种模型结构有点类似现实生活中铁链,由一个个铁环首尾相接构成一条链,如果这种结构用在编程领域,则每个节点可以看做一个对象,每个对象有不同的处理逻辑,将...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Linux系统CentOS6、CentOS7手动修改IP地址
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Windows10,CentOS7,CentOS8安装Nodejs环境