00:00
接下来我们就可以来编写秒杀商品的抢购功能,如果我们这个商品呢,正在秒杀活动中,我们可以在这儿来显示一个按钮,比如我们叫立即抢购,来点击这个按钮呢,就来开始秒杀,当然我们这个秒杀流程呢,我们市面上有比较常用的两种,首先第一种我们来看京东以及小米他们做的,如果我们这个京东里边,我们这个电脑呢,现在需要秒杀,秒杀呢它其实当成了一个优惠活动,它原来的价格呢是4999,现在呢是3358,如果我们想要购买这个商品这一块呢,并没有什么立即抢购,还是走我们正常的加入购物车逻辑,那么只要加入到购物车,那购物车里边商品的这个价钱,那就是我们当前这个商品的秒杀价格,所以我们在这儿去来结算的时候,那相当于购物车里边查到的这个价格,就按照它的秒杀价格来做就行了,这是我们说的第一种,那小米的这种呢也一样,比如我们现在呢,想要秒杀一个小米的这个路由器,我们选中了一个东西来点一。
01:00
呃,立即抢购,立即抢购呢,还是这个购物车流程,但如果不参与秒杀的这些商品,比如我们来随便点一个不参与秒杀的商品呢,下边呢,就是一个正常的加入购物车,也就是无论秒杀不秒杀,那都是一个加入购物车的流程,在购物车里边商品的价格呢,是秒杀的价格就行了,但无论我们使用哪种流程,我们都可以来做我们的秒杀。咱们来想,在我们这个秒杀业务呢,它最大的特点就是一个高并发,所以我们应该考虑的不是我们这个秒杀业务该怎么进行,而应该考虑的是我们如何设计一个高并发的系统,我们能承载住大量峰值流量,所以呢,我们来着重的讨论一下我们这个高并发系统里边一些问题和一些解决。比如我们这个以秒杀为例,在我们这个高并发系统里边呢,我们应该考虑这些问题,首先我们为了防止这个大量流量请求瞬间呢全部涌进来,把我们整个系统呢压垮,我们应该考虑以下这些问题,第一个问题,首先我们这个服务呢,应该满足服务单一职责原则,也就是说我们这个秒杀服务,我们现在是一个高并发的服务,我们最好把这个代码呢,不要跟其他混血们服务呢,单一职责,我们自个儿就干自个儿的专业事情,就来做秒杀,所以我们把这个单一的这个职责服务,我们来抽取过来,形成一个微服务,我们还可以来做独立部署,那即使我们这个秒杀这一块呢,它扛不住压力,也不要去来影响别人,所以这是我们需要做的第一点,第二点如果针对我们秒杀来说,我还是需要做到秒杀的链接加密,这个非常重要,假设呢,别人都知道我们这个秒杀会发什么请求过去,那我自己来写一个脚本,我写一个程序,我们每秒呢发上1000个请求,我。
02:46
或许呢,就来秒杀数据,这样就会出现问题,所以我们现在做的方式呢,就是秒杀的这个链接,你呢可以将链接直接加密,比如整个链接呢,生成一个MD5或者一个UUID就代表整个链接的值,这是第一种,我们在秒杀的时候呢,你才能看到。第二种就像我们做的,你虽然说你要秒杀的商品是哪个,你带了SQID,但是呢,每一个商品还有一个随机码,这个随机码呢,只有我们秒杀活动开始,我们这个页面呢才会给你返回,否则你是永远拿不到随机码,就没办法进行秒杀的,所以我们来使用第二种秒杀环境下链接加密。第三个特别针对于我们秒杀库存呢,要预热,要快速扣减,如果我们来走正常的加入购物车流程,然后呢去来占库存,然后最终去来支付,这样呢整个流程太慢了,在我们这个高并发系统里边肯定会出现整个接连崩溃的问题,所以我们现在呢,就应该做到一个预热库存,人们现在要秒杀的商品,我们数量呢已。
03:46
边有400件,那就像我们的定时任务,把这400个呢,只要一扫描进来,我们现在使用的是信号量,我们给red历里面存一个400的信号量,想要秒杀的人进来以后呢,我们先拿到信号,所以无论是我们几百万的请求,即使呢有400万的请求,最终呢,我们值有400个人能拿到这个信号量的值,所以我们最终呢放行到的是这400个人,把这400个人放行给我们后台的集群系统,然后呢,哪怕去来走,我们正常的加入购物车逻辑,这也不会出现我们很多的大问题,所以这是我们的关注的。第三点,库存的预热,我们提前呢,以缓存技术把它上到rabbit里边,然后快速扣减,我们在red里边使用信号量直接来增减一个数就行了,那特别是我们这一块呢,容易出现的问题就是我们red扛不住,那么现在一台red呢,可能单机并发就在2万到3万左右,那如果我们想要让他扛得住,那就可以来做集群,那做上十几台red的集群,让他能。
04:46
帮助百万这个并发,包括呢,我们red,最终我们来做成一个分片高可用,我们后来都会加上他们,还有我们来关心的第四点动静分离,这点呢也特别重要,无论是我们这个秒杀系统,还不是我们这个电商里边的其他普通正常业务,那么现在呢,都做到了一个动静分离,就是说所有的静态请求呢,直接是由NX,然后呢,给我们直接返回的NX里边的静态资源全部存在它里边,所以我们把NX呢,我们可以复制多份,那复制多份以后呢,我们随便访问哪个NG这个静态资源呢,直接都由N来返回,但如果是动态请求,除了所有的静态资源,动态请求呢,我们NG4才会路由到我们后台的网关,网关呢才会交给我们的微服务,只要动静一分离,假设只有100万请求进来,我们现在秒杀100万,那现在呢,可能是这样的100万,我们秒杀呢,都要来商品详情页,我一刷新这一个页面请求数非常多,我们来看一下,我来点一个刷新,我们会。
05:46
那么呢,其实有这么多请求,真正的核心请求就这一个1.htm,剩下都是一些静态资源,那合起来呢,有63个,假设我们即使有一个10万的人去来访问我们这个商品详情页,其实请求数量呢是630万,所以呢,这是我们这个大并发又一产生的原因,那么想要来搞定这个,我们就来做好动静分离,那么现在呢,加入了NG斯的动静分离,或者呢,如果我们上线以后,更好的条件就是使用CDN来做我们的压力承担,然后我们现在的这些所有的静态资源,我们全部将这些静态资源呢,我们可以分享给我们这个CDN网络,比如我们随便使用阿里云,我让阿里云来保存这些静态资源,这静态资源呢,阿云会放进各个服务节点,比如我们现在呢,有一个上海节点,还有北京节点,还有杭州节点,那接下来如果我们访问我们的静态资源,我们阿里云会就近来选择一个快最快的节点给我们来返回这个静态资源。所以我们也可以来使。
06:46
用这个CP网络,这是我们说的动静分离,那做好了动静分离以后呢,压给我们后台的请求就不多了,因为把静态请求过滤了,能放过来的动态请求那63个放一个,这多正常的,然后接下来这是我们说的第四个,那第五个咱们高并发请求系统里边呢,特别要注意恶意请求的拦截,那对于我们这个高并发系统,我们这个恶意请求呢,我们说也有很多种,比如我们说的第一种情况,我们就是一个恶意脚本,我们每秒呢发1000次,就来给我们来发送秒杀请求,或者呢,就是我们这个脚本每秒呢发1000次访问一号的这个商品信息,要这个页面数据,但我们会发现其实按照正用户正常的这个流量访问他呢,在这儿刷的再快,每秒呢,可能也就五六次,所以每秒这个1000次,肯定是有别的脚本来模拟我们这个访问所,我们应该把这些恶意请求拦截过去,还有一些伪造的请求,比如我们好多请求呢,需要带一些。
07:46
牌他不带令牌,在这呢,直接给我们伪造过来,我们也应该直接拦截过来,所以一句话,我们只要一经过网关以后,放给我们后台的整个请求应该是一个具有正常行为的,所以我们恶意请求的拦截最好呢是在网关层拦截啊,写一个网关层,那么在网关层一栏以后呢,放给后台集群的又是一些正常请求,我们又过滤了一些,包括我们说的流量错峰,这个非常重要,在我们这个秒杀系统里边,我们现在来想,如果我们现在大家都来秒杀,我来点一个立即抢购,现在就是100万人同时点了立即抢购,那么现在的瞬间流量那就是100万,我们就得想办法处理,他们可以通过一些技术,让他整个瞬间的100万流量,我们比如画一个图是这样,这一秒的流量达到100万,我让这个瞬间100万,我分散到其他各种几秒。
08:41
比如呢,小米以前做的一个秒杀的细节,就是我们在这呢,点一个立即抢购,抢购完了以后呢,我们让你输入一个验证码,这验证码呢有两个好处,第一个,那么这个验证码呢,来区分是机器还是人人识别了验证码输了以后,那么这个请求才是正常的,机器识别不了,他提交这个请求是非法的,这是第一种过滤,第二种,大家想啊,我们这个人输验证码呢,我们输的速度有快有慢,输完点击提交,那相当于我们点一个立即抢购到服务端,真正的收到我们这个抢购请求的时候,我们现在呢,有100万用户,可能呢,这10万是在一秒内输完的,然后呢,这10万是在两秒内输完的,所以我们相当于把整个流量呢就分散开了,不是说这一秒直接集中100万,而是呢,我们现在成了这么一个峰值活动,所以说呢,每秒有它的这个大量请求,但我们相当于就错开了。
09:38
我们把100万呢,时间分散到了各个时间点上,这是们说的流量错分,这也很重要,我们引入验证码机制,或者我们说的这个加入购物车机制就非常好,我们呢选中了这个商品,我点了加入购物车,那你要结账,要锁库存,这还有一串的时间,所以呢,这个时间段呢,大家的操作快慢都不一样,所以我们又把流量呢又错开,我们分摊到各个时间轴上了,所以这是我们说的流量错峰,包括我们说的限流,熔断、降级,那在我们这个高并发系统里边呢,这个一定要考虑,那么现在要设计秒杀,那秒杀呢,可能要远程调用其他的服务,包括秒杀自己进来的流量也很大,所以我们先首先要做的第一个就是限流,限流呢,有前端限流与后端限流很多,前端限流最典型的方式那就是这样,比如我们现在在商城里边,我们想要秒杀我们的这个手机来点进来,那前端限流呢,我们这有一个秒杀按钮,我们点一个。
10:39
立即抢购,我点一下,那前端想要限流,那就应该是点一下,我们一秒以后呢才能点第二下,或者呢点第三下,或者呢点一下就不能再点了,所以这是我们前端限流,通过前端的限流,我们可以限制一部分的流量,当然如果我们知道点了这个按钮发什么请求,我们继续拿恶意脚本去来无限次的访问,他呢也限不住,所以呢,前端限流先防止上一些,再来到我们这个后台,我们后台呢,可以来识别一些哪些是用户的正常行为,哪些一些是恶意行为,那么再来给他进行过滤,包括一过滤进来,即使你是用户的正常行为,我也给你限流,你用户的正常行为一秒你点了十来次,我们现在呢,只给你放心上一两次,所以我们最终可以通过限流把大量的请求,那现在呢,有100万大量的请求,把一些不合理的去除掉,比如我们剩60万,再把这60万呢,有些用户一秒点了十次,我们给他放过一次,我来放过上个1/10。
11:39
又剩了6万,所以我们呢,通过一步一步的操作,每到达一层,无论是什么页面层,后台,我们都给它来做一个限流操作,把不合理的过滤掉,哪怕你是合理的,你次数太多了,我也给你限制起来,所以呢,我们最终给后台集群里边放的流量就很少,我们可以限制次数,限制总量,比如我现在知道我秒杀呢,现在在四个机器,五个机器里边有我现在的峰值处理能力,那就是10万,所以呢,我就可以来在网关层做一个总限流,只要你发给我们秒杀服务的所有流量,那不能超过10万,超过10万了你就等上两秒,等上两秒以后呢,再给我把请求转过去,所以我们就可以来做这个限流操作,包括我们这个熔断降级也非常重要,因为现在这个秒杀我们可能要调用其他业务,那么这个其他业务我们A来调用BB,再来调用C,如果呢,我们这个B经常调用失败,所以我们经常呢要让B给他。
12:39
做一个断路保护,我们知道呢,B经常调用失败了,那我们下一次呢,就不尝试调币了,要不然一直在这阻塞等待,本来我们这个请求按照正常调用过来,0.1秒我们就得到释放了,我们就可以来处理下一个请求了,但现在一直阻塞了三五秒后才释放,才告诉我们这个失败了,那就不合理,所以我们跟他就来加入熔断机制,我们只要来调用量的任何一个人出现问题,比如我们这个D出现了问题,我们就给他返回快速失败,C调用D,那快速的返回我们这个R对象,比如它的code的那就是一,那就是一个失败,这样一失败以后呢,能保证我们整个调用量是一个快速返回的,而不是大家在这儿等它的整个返回结果,所以我们这个熔断呢,先保证我们快速的失败,再来加上如果这出现问题了,我们把它一断路以后呢,相当于就把它隔离了,不去来影响别人,再来加上如果我们自己的服务出现问题,我们也可以给它降级运行,比如这个流量太大了,我们这个秒杀。
13:39
服务呢将要被压垮了,我们可以将一部分的流量直接引导到一个降级页面,说我们当前服务太忙,请稍后再访问,这呢也是我们的一种手段,再加上一个最后的杀手锏,我们使用队列消峰,你无论是流量再大,你哪怕呢有1000万,只要我能收得住请求,那我只要呢一收进来,本来我们要调用创建订单支付,可能呢这一串逻辑,特别是创建订单也很慢,还要扣库存,那么这串逻辑呢,本来要正常执行起来,可能要三秒五秒的或者两秒的,但我们现在呢,只要请求收到,你这个是合法的,你能秒杀,比如我们现在呢,有100个库存,我们放给后台集群,我们这放过来呢,放给了100万个人,这100万个人都要秒杀。
14:25
要争抢这100个库存,那么现在呢,别去数据库争抢们所有的库存呢,去red放了信号量,所以这100人呢来抢信号量,这100万个只有100个人能抢到信号量,信号量的扣减非常快,就是给一个数值减个一,大家都在统一的red里边操作,也不可能出现那这个信号量超扣的问题,因为它最多就能扣到零,这是一个原子操作,所以我们拿到这个信号量的值以后,只要能拿到信号量的人,我们来接下来放行给我们的后台,这个后台呢,我们可以直接将请求发给一个队列,然后呢,我们的订单服务就来监听我们这个秒杀队列,只要秒杀的请求能被放进队列里边的,那他呢,订单服务就在这儿,后台慢慢创建订单,创上五秒十秒的都行。
15:11
我们现在呢,就告诉你秒成功了,你五分钟以后看你的这个控制台去来支付这个订单都行,所以我们来可以引入这个队列,特别是对于我们这个场景,如果是我们这个单品秒杀无所谓,我们这一个商品,比如就一个iPhone叉,我们就这一个商品100件秒杀,因为我们这能放进来的请求就100个,我们通过信号量一控制以后,放进来100个,这100个走正常流程都没问题,但我们现在假设是淘宝的双11,我们到12点凌晨12点,现在淘宝全网的所有商品,可能几百万件商品,每一个商品呢,它呢都假设有100万的库存。那么假设有100个库存,不应该是100万,然后现在呢,大家用户都来秒杀这些商品,所以每一个商品放进来100个,100万的商品放进来的那就是11个亿的流量,那就进来了,所以这个时候队列的作用就特别明显,所以请求一进来,只要你能秒成功,这个东西呢,你抢到货了,那我就把这个放到队列里边,我们整个后台的订单集群就来监听这个队列,队列里边呢,我们做好整个集群化,存上它几万亿的数据都没任何问题,放进队列里边的,那后边的集群呢,慢慢按照自己的能力来进行消费,反正无论怎么消费,那一分钟后你肯定见到结果了,所以最终你的这个订单可能会出现延迟,但是呢,你最终都能支付成功,所以这呢,也就是我们的杀手锏队列消峰,所以整个一个高并发系统里边,我们要设计的话,就要考虑这么多问题,特别我们秒杀服务更多要考虑秒杀服务呢,是一个高并发系统的代表。我们不能只。
16:49
局限于它的这个秒杀,那我们正好来看一下我们都做了哪些,首先呢,我们做了第一个场景,就是服务的单一职责,那现在将秒杀单独抽取出来了,我们现在编专门编写了一个秒杀服务,我们不让它影响别人。第一个第二个呢,我们也来做了整个秒杀链的加密功能,这个加密呢,我们是使用一个随机码,只有我们这个秒杀时间到了,你才能收到我们这个随机码,你拿着这个随机码才可以来进行秒杀,所以我们就不害怕别人去来做恶意攻击,你提前在这儿前十分钟就开始运行给我们发请求来秒,但是你没有这个随机码,那是没用的。接下来我们来说的第三个库存预热快速扣减,这个呢我们也加上了,因为我们将所有的库存信息,我们要秒杀的这个商品,我们使用一个定时任务一上架,上架以后呢,它要秒杀多少件库存,是放在red里边来做一个信号量控制,也就是一个原子减量,只要呢,来一个数我们就原子减一,来一个我们就原子减一。
17:49
最终呢,我们能放过的这个请求数,那就是它的秒杀量,这是这个我们也做到动静分离,我们从一开始就做到了,那其他业务呢,也都做到了东京分离,那接下来关注到后续问题,恶意请求拦截,那接下来我们就要处理包括流量的错峰,那如果我们使用整个加入购物车逻辑,那流量呢也就错分开了,还有我们的限流,熔断、降级,这个是我们接下来要着重讨论的问题,以及队列消分,我们只要你拿到这个抢购资格了,我们可以将整个抢购请求放到队列里边,由订单服务来监听,自己来创建这个订单,所以我们后续呢,再来加上这节课就行了,那下一节课我们就来完善我们的整个秒杀逻辑。
我来说两句