回答这份秒杀攻略,99.9%的面试官会给你比大拇指

对不起又标题党啦!不过这里想说的是,做互联网行业的应该保持一颗谦虚的心灵,毕竟你知道的越多,你不知道的也越多,不是吗?唯有不断学习,才是我们码农的最终归宿。

前言

设计一个秒杀系统,到底需要考虑哪些问题呢?相信不少同学在面试的时候都会被问到这个问题,接下来就让我带领大家一起从浅入深学习一下秒杀的特性,常见的问题与解决方案。
在这里插入图片描述

秒杀的特性

用过某宝,某东之类的电商产品的朋友肯定对一般的电商流程是了然于心的,不外乎就是先查询一下商品卖完了没有,没卖完就创建订单,然后去扣减库存,接着更新订单,在一段时间内要完成付款操作,最后付款之后商家会尽快发货。

在流程上,秒杀其实与正常的电商流程是大同小异的,只不过秒杀的特性会决定在一段极短的时间内会有大量的用户访问,也就是我们常说的高并发。一般来说,如果是某宝搞的秒杀活动,来个几十万流量不成问题吧,如果放任这些流量直接打到 DB 上,我们的服务器肯定是顶不住的,就算使用 Redis,由于单机的 Redis 大概只能够有 3-4W 的 QPS,肯定还是远远不够的。下面我们来考虑一下,应该怎么设计一个秒杀系统,保护我方服务器,消化掉这些流量?

秒杀带来的问题与解决方案

秒杀之前

在秒杀开始之前,为了不错过秒杀,大部分用户都有不断刷新浏览器页面的习惯(我也有。。)。正常来说,这样一直刷新,会一直访问应用服务器,对其造成负载压力(废话,几十万人一直刷,谁承受的了!)

那么如何解决呢?可以通过页面内容静态化(页面可以缓存在 CDN 服务器上)来解决这个问题,让用户请求不需要经过应用服务,这样岂不皆大欢喜?另一个需要注意的点是,购买按钮也需要在秒杀之前置灰,当秒杀开始时才点亮,这也是为了防止用户一直点购买按钮,给服务器带来压力。

对现有的业务造成冲击

秒杀一般只是网站营销的一个附属,毕竟电商不可能天天秒杀对不对,肯定得有自己正常的业务吧。由于秒杀高并发的特性,非常容易会对现有的业务造成冲击。

我们想想,如果把秒杀系统与网站的其它系统部署在一起,秒杀系统挂了,网站的其它系统估计也跑不了,那这个网站不就当场去世了?对于电商来说,这得损失多少钱啊!所以,秒杀系统只能独立部署吧,得与网站其它系统完全隔离,你挂了就算了,可别连累兄弟们啊!

超卖

秒杀一般都是不怎么赚钱的,大部分都是赔本赚吆喝,如果你卖的是日用品之类的还好,倒霉的话你卖的是什么手机,电脑啊,发生超卖是很恐怖的。你本来只想卖50个,想着亏点小钱赚点名声,结果好了,程序有 bug,直接卖了1000个,这不直接原地爆炸?

至于如何解决,我们要么引入锁,要么尝试扣减库存,只有在扣减库存成功之后才会进行下单逻辑。这个在这里大家留个印象就好了,在下面的部分我会详细介绍。

恶意请求

你搞个秒杀得做宣传吧,这个宣传用户可以看到,一些别有用心的人没理由看不到啊,这么低的价格,他们买下来,再转手卖掉,岂不是血赚?

这些别有用心的人搞几台机器,搞个脚本,模拟个几十万人的请求,成功率不比你们这些小用户高的多?就像演唱会,春运高铁票之类的一个性质,只要黄牛参加抢票了,票子肯定都是秒光的,毕竟机器还是比人手要先进一点的。如果我们的秒杀不加以控制,说不定全部商品都被这些人抢去了,也不是一件稀奇的事情呢。

这类恶意请求一般每秒的请求次数非常夸张,绝对不是正常人可以有的手速,我们可以在网关层 Nginx 加以拦截,不然的话,他抢不抢的到倒是另一回事,这么多的请求会给服务器带来巨大的压力,把服务器打崩也未可知。

链接暴露

懂点代码的人如果想 “作弊”,也不难,直接用谷歌的开发者模式看你的网页代码就好了,说不定里面就有 URL,有了这个 URL,可以做的事情就太多了,这个不用我教了吧(一脸坏笑)?

又或者,日防夜防,家贼难防,你开发对商品动心了咋办?开发总得知道地址吧,在秒杀的时候提前请求,这怎么防?

其实我们可以将 URL 动态化,即使开发也无法在秒杀开始前得到秒杀页面的 URL。那么话说回来,我们如何将 URL 动态化呢?这里提供一种思路,可以在 URL 加入随机数作为参数,在秒杀开始时才能得到。

数据库问题

我们上面说过了,正常大一点的秒杀活动来个几十万的流量不成问题,QPS 可能达到六位数的级别,直接打到数据库上,我怀疑你的数据库可能会当场去世。
在这里插入图片描述

我们考虑一下这个流程,一个用户的请求进来,你就去数据库查询一下库存,这好像不太 ok 吧,那怎么办?

这么多的流量数据库虽然顶不住,但是它的兄弟 Redis 却是可以承受的!有读者可能会问,咦,你不是说,单机的 Redis 只有 3-4W 的 QPS,这怎么顶啊!打架总打过吧,一个人打不过,就叫一群人来呗,Redis 同理啊,单机的搞不定,我弄个 Redis 集群,这下总顶的住吧。

在秒杀开始之前,我们搞一个定时任务,提前把商品的库存加载到 Redis 里面去,整个流程就在 Redis 中操作,秒杀结束之后再异步去修改库存就好了。

但是,新的问题出现了!如果库存只剩下一个,这时候十个请求进来,分别在十个服务器中进行查询,发现库存还有。美滋滋地直接去扣库存,结果直接变成了 -9,也就是我们上面提到的超卖,这可怎么办?

可以使用 Lua 脚本来解决这个问题,好,问题来了,什么是 Lua 脚本呢?Lua 脚本类似于 Redis 事务,有一定的原子性,不会被其他命令插队,可以完成一些 Redis 事务性的操作。 我们可以写一个 Lua 脚本,里面包含判断库存和扣减库存的逻辑,然后弄一个开关,库存到0之后修改一下开关,直接拦住全部请求,完美!

巨大流量

秒杀自带高并发属性,一秒几十万的流量不是梦,这么大的流量,我们总得做点什么,不能让服务器照单全收吧。

其实这个好办,我们搞个限流就行了,其中限流又分前端限流和后端限流,那么这两者有什么区别呢?

前端限流就是按钮不能让你一直点,点了一下之后就得等一段时间之后才能继续点击,也是为了保护服务器,后端限流就是当产品卖完之后,就直接 return false,拒绝后续请求就好了。

关于限流,我们还可以加入限流组件,例如 Hystrix 之类的。

除了限流,我们还可以搞搞别的花样,例如做个降级,熔断,隔离之类的,这些都是在设计系统的时候需要考虑的。

从另外一个角度考虑,商品数量只有几百个的时候,直接改库没有问题,但如果商品数量上去了呢?怎么办?为了保护服务器,我们可以采取削峰填谷的策略,将请求放进消息队列中,然后慢慢消费,慢慢修改库存就好了嘛。

总结

要设计一个秒杀系统并不是那么容易的,要考虑的问题非常多,把上面我提到的问题解决了,设计一个小型的系统应该不成问题,不过要是精益求精,最好还是得多考虑一些别的问题(毕竟,博主只是说让99.9%的面试官比大拇指,并没说100%啊哈哈哈),多思考,多动手,多实践,这才是程序员进阶的正确打开方式。
在这里插入图片描述

参考:阿里面试官问我:如何设计秒杀系统?我的回答让他比起大拇指
秒杀系统架构分析与实战

原创文章 155 获赞 323 访问量 4万+

猜你喜欢

转载自blog.csdn.net/Geffin/article/details/105670934