实际作过企业项目商品秒杀系统的人告诉你,秒杀系统的实际设计方案

敖丙谈商品秒杀系统

看题目也知道,这是转载的,非原创,这是我关注的一位大佬在公众号发的,研读了一遍,真的是特别全面,想看原做者能够在微信搜索:三太子敖丙
这位95年的老哥实在太强前端

背景

我以前写过一个秒杀系统的文章不过有些许瑕疵,因此我准备在以前的基础上进行二次创做,不过让我决心二创秒杀系统的缘由是我最近面试了不少读者,动不动就是秒杀系统把我整蒙蔽了,我懵的主要是秒杀系统的细节你们都不知道,甚至不知道电商公司一个秒杀系统的组成部分。
我以前在某电商公司就是作电商活动的,因此这样的场景和不少解决方案我是比较清楚的,那我就从我自身去带着你们看看一个秒杀的设计细节以及中间各类解决方案的利弊,如下就是我设计的秒杀系统,几乎涵盖了市面上全部秒杀的实现细节:node

正文

首先设计一个系统以前,咱们须要先确认咱们的业务场景是怎么样子的,我就带着你们一块儿假设一个场景好吧。
咱们现场要卖1000件下面这个婴儿纸尿裤,而后咱们根据以往这样秒杀活动的数据经验来看,目测来抢这100件纸尿裤的人足足有10万人。(南极人打钱!)程序员

你一听,完了呀,这咱们的服务器哪里顶得住啊!说真的直接打DB确定挂,可是别急嘛,有暖男敖丙在,任何系统咱们开始设计以前咱们都应该去思考会出现哪些问题?这里我罗列了几个很是经典的问题:
问题web

高并发:

是的高并发这个是咱们想都不用想的一个点,一瞬间这么多人进来这不是高并发何时是呢?
是吧,秒杀的特色就是这样时间极短、 瞬间用户量大面试

正常的店铺营销都是用极低的价格配合上短信、APP的精准推送,吸引特别多的用户来参与这场秒杀,爽了商家苦了开发呀。算法

秒杀你们都知道若是真的营销到位,价格诱人,几十万的流量我以为彻底不是问题,那单机的Redis我感受3-4W的QPS仍是能顶得住的,可是再高了就没办法了,那这个数据随便搞个热销商品的秒杀可能都不止了。数据库

大量的请求进来,咱们须要考虑的点就不少了,缓存雪崩,缓存击穿,缓存穿透这些我以前提到的点都是有可能发生的,出现问题打挂DB那就很难受了,活动失败用户体验差,活动人气没了,最后背锅的仍是开发。小程序

超卖:

但凡是个秒杀,都怕超卖,我这里举例的只是尿不湿,要是换成100个MacBook Pro,商家的预算经费卖100个能够赚点还能够造势,结果你写错程序多卖出去200个,你不发货用户投诉你,平台封你店,你发货就血亏,你怎么办?(没事看了敖丙的文章直接不怕)后端

那最后只能杀个开发祭天解气了,秒杀的价格原本就低了,基本上都是不怎么赚钱的,超卖了就恐怖了呀,因此超卖也是很关键的一个点。缓存

恶意请求:

你这么低的价格,假如我抢到了,我转手卖掉我不是血赚?就算我不卖我也不亏啊,那用户知道,你知道,别的别有用心的人(黑客、黄牛…)确定也知道的。
那简单啊,我知道你何时抢,我搞个几十台机器搞点脚本,我也模拟出来十几万我的左右的请求,那我是否是意味着我基本上有80%的成功率了。
真实状况可能远远不止,由于机器请求的速度比人的手速每每快太多了,在贵州的敖丙我每一年回家抢高铁票都是秒光的,我也不知道有没有黄牛的功劳,我要Diss你,黄牛。杰伦演唱会门票抢不到,我也Diss你。
Tip:科普下,小道消息了解到的,黄牛的抢票系统,比国内不少小公司的系统还吊不少,架构设计都是顶级的,我用顶配的服务加上顶配的架构设计,你还想看演唱会?还想回家?
不过不用黄牛我回家都难,咱们云贵川跟我同样要回家过年的仔太多了555!

连接暴露:

前面几个问题你们可能都很好理解,一看到这个有的小伙伴可能会比较疑惑,啥是连接暴露呀?

相信是个开发同窗都对这个画面一点都不陌生吧,懂点行的仔均可以打开谷歌的开发者模式,而后看看你的网页代码,有的就有URL,可是我写VUE的时候是事件触发而后去调用文件里面的接口看源码看不到,可是我能够点击一下查看你的请求地址啊,不过你好像能够对按钮在秒杀前置灰。
无论怎么样子都有危险,撇开外面的全部的东西你都挡住了,你卖这个东西实在便宜得过度,有诱惑力,你能保证开发不动心?开发知道地址,在秒杀的时候本身提早请求。。。(开发:怎么TM又是我)

数据库:

每秒上万甚至十几万的QPS(每秒请求数)直接打到数据库,基本上都要把库打挂掉,并且你服务不仅仅是作秒杀的还涉及其余的业务,你没作降级、限流、熔断啥的,别的一块儿挂,小公司的话可能全站崩溃404
反正无论你秒杀怎么挂,你别把别的搞挂了对吧,搞挂了就不是杀一个程序员能搞定的。
程序员:我TM好难啊!
问题都列出来了,那怎么设计,怎么解决这些问题就是接下去要考虑的了,咱们对症下药。
我会从我设计的秒杀系统从上到下去给你们介绍咱们正常电商秒杀系统在每一层作了些什么,每一层存在的问题,难点等。
咱们从前端开始:

前端

秒杀系统广泛都是商城网页、H五、APP、小程序这几项。
在前端这一层其实咱们能够作的事情有不少,若是用node去作,甚至能直接处理掉整个秒杀,可是node其实应该属于后端,因此我不讨论node Service了。

资源静态化:

秒杀通常都是特定的商品还有页面模板,如今通常都是先后端分离的,页面通常都是不会通过后端的,可是前端也要本身的服务器啊,那就把能提早放入cdn服务器的东西都放进去,反正把全部能提高效率的步骤都作一下,减小真正秒杀时候服务器的压力。

秒杀连接加盐:

咱们上面说了连接要是提早暴露出去可能有人直接访问url就提早秒杀了,那又有小伙伴要说了我作个时间的校验就行了呀,那我告诉你,知道连接的地址比起页面人工点击的仍是有很大优点
我知道url了,那我经过程序不断获取最新的北京时间,能够达到毫秒级别的,我就在00毫秒的时候请求,我敢说绝对比你人工点的成功率大太多了,并且我能够一毫秒发送N次请求,搞很差你卖100个产品我全拿了。

那这种状况怎么避免?
简单,把URL动态化,就连写代码的人都不知道,你就经过MD5之类的摘要算法加密随机的字符串去作url,而后经过前端代码获取url后台校验才能经过。
这个只能防止一部分没耐心继续破解下去的黑客,有耐心的人研究出来仍是能破解,在电商场景存在不少这样的羊毛党,那怎么作呢?
后面我会说。

限流:

限流这里我以为应该分为前端限流后端限流
物理控制
你们有没有发现没到秒杀前,通常按钮都是置灰的,只有时间到了,才能点击。
这是由于怕你们在时间快到的最后几秒秒疯狂请求服务器,而后还没到秒杀的时候基本上服务器就挂了。
这个时候就须要前端的配合,定时去请求你的后端服务器,获取最新的北京时间,到时间点再给按钮可用状态。
按钮能够点击以后也得给他置灰几秒,否则他同样在开始以后一直点的。
你敢说大家秒杀的时候不是这样的?

前端限流:这个很简单,通常秒杀不会让你一直点的,通常都是点击一下或者两下而后几秒以后才能够继续点击,这也是保护服务器的一种手段。
后端限流:秒杀的时候确定是涉及到后续的订单生成和支付等操做,可是都只是成功的幸运儿才会走到那一步,那一旦100个产品卖光了,return了一个false,前端直接秒杀结束,而后你后端也关闭后续无效请求的介入了。
Tip:真正的限流还会有限流组件的加入例如:阿里的Sentinel、Hystrix等。我这里就不展开了,就说一下物理的限流。
咱们卖1000件商品,请求有10W,咱们不须要把十万都放进来,你能够放1W请求进来,而后再进行操做,由于秒杀对于用户自己就是黑盒的,因此你怎么作的他们是没感知的,至于为啥放1W进来,而不是恰好1000,是由于会丢掉一些薅羊毛的用户,至于怎么判断,后面的风控阶段我会说。

Nginx:

你们想必都不陌生了吧,这玩意是高性能的web服务器,并发也随便顶几万不是梦,可是咱们的Tomcat只能顶几百的并发呀,那简单呀负载均衡嘛,一台服务几百,那就多搞点,在秒杀的时候多租点流量机
Tip:据我所知国内某大厂就是在去年春节活动期间租光了亚洲全部的服务器,小公司也很喜欢在双十一期间买流量机来顶住压力。

这样一对比是否是以为你的集群能顶不少了。
恶意请求拦截也须要用到它,通常单个用户请求次数太夸张,不像人为的请求在网关那一层就得拦截掉了,否则请求多了他抢不抢获得是一回事,服务器压力上去了,可能占用网络带宽或者把服务器打崩、缓存击穿等等。

风控

我能够明确的告诉你们,前面的全部措施仍是拦不住不少羊毛党,由于他们是专业的团队,他们能够注册不少帐号来薅你的羊毛,并且不用机器请求,就用群控,操做几乎跟真实用户如出一辙。

那怎么办,是否是无解了?
这个时候就须要风控同窗的介入了,在请求到达后端以前,风控能够根据帐号行为分析出这个帐号机器人的几率大不大,我如今负责公司的某些特殊系统,每一个用户的行为都是会送到咱们大数据团队进行分析处理,给你打上对应标签的。
那黑客其实也有办法:养号
他们去黑市买真实用户有过不少记录的帐号,买到了还不闲着,帮他们去购物啥的,让系统没法识别他们是黑号仍是真实用户的号。
怎么办?
通杀!是的没有办法,只能通杀了,通杀的意思就是,咱们经过风管分析出来这个用户是真实用户的几率没有其余用户几率大,那就认为他是机器了,丢弃他的请求。
以前的限流咱们放进来10000个请求,可是咱们真正的库存只有1000个,那咱们就算出最有多是真实用户的1000人进行秒杀,丢弃其余请求,由于秒杀原本就是黑盒操做的,用户层面是无感知的,这样设计能让真实的用户买到东西,还能够减小本身被薅羊毛的几率。
风控能够说是流量进入的最后一道门槛了,因此不少公司的风控是很强的,蚂蚁金服的风控你们若是了解过就知道了,你的资金在支付宝被盗了,他们是能作到全款补偿是有缘由的。

后端

服务单一职责:
设计个能抗住高并发的系统,我以为仍是得单一职责
什么意思呢,你们都知道如今设计都是微服务的设计思想,而后再用分布式的部署方式
也就是咱们下单是有个订单服务,用户登陆管理等有个用户服务等等,那为啥咱们不给秒杀也开个服务,咱们把秒杀的代码业务逻辑放一块儿。
单一职责的好处就是就算秒杀没抗住,秒杀库崩了,服务挂了,也不会影响到其余的服务。(高可用)

Redis集群:

以前不是说单机的Redis顶不住嘛,那简单多找几个兄弟啊,秒杀原本就是读多写少,那大家是否是瞬间想起来我以前跟大家提到过的,Redis集群,主从同步、读写分离,咱们还搞点哨兵,开启持久化直接无敌高可用!

库存预热:

秒杀的本质,就是对库存的抢夺,每一个秒杀的用户来你都去数据库查询库存校验库存,而后扣减库存,撇开性能因数,你不以为这样好繁琐,对业务开发人员都不友好,并且数据库顶不住啊。
开发:你tm总算为我着想一次了。

那怎么办?
咱们都知道数据库顶不住可是他的兄弟非关系型的数据库Redis能顶啊!
那不简单了,咱们要开始秒杀前你经过定时任务或者运维同窗提早把商品的库存加载到Redis中去,让整个流程都在Redis里面去作,而后等秒杀结束了,再异步的去修改库存就行了。
可是用了Redis就有一个问题了,咱们上面说了咱们采用主从,就是咱们会去读取库存而后再判断而后有库存才去减库存,正常状况没问题,可是高并发的状况问题就很大了。
**多品几遍!!!**就好比如今库存只剩下1个了,咱们高并发嘛,4个服务器一块儿查询了发现都是还有1个,那你们都以为是本身抢到了,就都去扣库存,那结果就变成了-3,是的只有一个是真的抢到了,别的都是超卖的。咋办?

事务:

Redis自己是支持事务的,并且他有不少原子命令的,你们也能够用LUA,还能够用他的管道,乐观锁他也支持。
限流&降级&熔断&隔离:
这个为啥要作呢,不怕一万就怕万一,万一你真的顶不住了,限流,顶不住就挡一部分出去可是不能说不行,降级,降级了仍是被打挂了,熔断,至少不要影响别的系统,隔离,你自己就独立的,可是你会调用其余的系统嘛,你快不行了你别拖累兄弟们啊。

消息队列(削峰填谷):

一说到这个名词,不少小伙伴就知道了,对的MQ,你买东西少了你直接100个请求改库我以为没问题,可是万一秒杀一万个,10万个呢?服务器挂了,程序员又要背锅的。
秒杀就是这种瞬间流量很高,可是平时又没有流量的场景,那消息队列彻底契合这样的场景了呀,削峰填谷。

Tip:可能小伙伴说咱们业务达不到这个量级,不必。可是我想说咱们写代码,就不该该写出有逻辑漏洞的代码,至少之后公司体量上去了,别人一看竟然不用改代码,一看代码做者是敖丙?有点东西!
你能够把它放消息队列,而后一点点消费去改库存就行了嘛,不过单个商品其实一次修改就够了,我这里说的是某个点多个商品一块儿秒杀的场景,像极了双十一零点。

数据库

数据库用MySQL只要链接池设置合理通常问题是不大的,不过通常大公司不缺钱并且秒杀这样的活动十分频繁,我以前所在的公司就是这样秒杀特卖这样的场景一直都是不间断的。
单独给秒杀创建一个数据库,为秒杀服务,表的设计也是竟可能的简单点,如今的互联网架构部署都是分库的。
至于表就看你们怎么设计了,该设置索引的地方仍是要设置索引的,建完后记得用explain看看SQL的执行计划。(不了解的小伙伴也没事,MySQL章节去康康)

分布式事务

这为啥我不放在后端而放到最后来说呢?
由于上面的任何一步都是可能出错的,并且咱们是在不一样的服务里面出错的,那就涉及分布式事务了,可是分布式事务你们想的是必定要成功什么的那就不对了,仍是那句话,几个请求丢了就丢了,要保证时效和服务的可用可靠。
因此TCC和最终一致性其实不是很适合,TCC开发成本很大,全部接口都要写三次,由于涉及TCC的三个阶段。
最终一致性基本上都是靠轮询的操做去保证一个操做必定成功,那时效性就大打折扣了。
你们以为不那么可靠的**两段式(2PC)和三段式(3PC)**就派上用场了,他们不必定能保证数据最终一致,可是效率上还算ok。

总结

到这里我想我已经基本上把该考虑的点还有对应的解决方案也都说了一下,不知道还有没有没考虑到的,可是就算没考虑到我想我这个设计,应该也能撑住一个完整的秒杀流程。
最后你们再看看这个秒杀系统或许会有新的感悟,是否是一个系统真的没有你们想的那么简单,并且我仍是有漏掉的细节,这是必定的。

秒杀这章我脑细胞死了不少,考虑了不少个点,最后仍是出来了,忍不住给本身点赞!

总结2

咱们玩归玩,闹归闹,别拿面试开玩笑。
秒杀不必定是每一个同窗都会问到的,至少确定没Redis基础那样常问,可是一旦问到,你们必定要回答到点上。
至少你得说出可能出现的状况,须要注意的状况,以及对于的解决思路和方案,由于这才是一个coder的基本素养,这些你不考虑你也很难去进步。 最后就是须要对整个链路比较熟悉,注意是一个完整的链路,前端怎么设计的呀,网关的做用呀,怎么解决Redis的并发竞争啊,数据的同步方式呀,MQ的做用啊等等,相信你会有不错的收获。 不知道这是一次成功仍是失败的二创,我里面全部提到的技术细节我都写了对应的文章,你们能够关注我去历史文章看看,天色已晚,我溜了。 我是敖丙,你知道的越多,你不知道的越多,咱们下期见!