00:00
前面我们编写完了秒杀系统的核心代码,那为了保证我们这个秒杀高并发系统的性能,那我们引入了非常多的设计因素,比如第一个我们首先保证我们秒杀服务的单一职责,我们为它专门创建了一个微服务,而且我们还会独立部署,这样的话呢,我们这个秒杀服务其实出现问题,我们也不要去影响别人。那第二个我们也引入了秒杀链接加密机制,我们是引入了一个随机码机制,那么需要秒杀的这个商品,只要到了秒杀时间,你才能可以获取到它的随机码,那有了这个随机码以后,带上我们这个随机码来进行秒杀,那我们就天然的预防了一些恶意攻击,比如他来提前来做一个尝试,知道我们秒杀要发什么kill请求,他提前尝试,但不知道随机码,我们验证不通过就不来秒杀,包括呢,我们也防止我们这个一些内部的漏洞,各种问题,然后呢,包括第三个我们引入了库存预热,快速扣减,其实这个就是我说。
01:01
我们使用了缓存,因为我们把整个秒杀的商品数据我们放到了缓存red里边,我们直接扣缓存里边的这个信号量,我们比如要秒杀100件,每来上两件,一件我来扣一些信号量,要比我们去数据库里边扣库存要快得多,从使用缓存技术保证了它的快,我们只有能非踌速的执行完了以后,我们才可能释放掉我们这个资源,我们才能允许新的请求进来,所以吞吐量的上升,这就是第一个方便,我们保证我们每一个方法都很快,我们自己执行完,那能去执行别人了,我们整个吞吐量就上去了,而且我们还引了我们的动静分离,比如我们现在呢?全系统我们都是使用NX来做了动静分离,静态资源呢,我们直接NX返回动态资源,我们才需要打到我们的后台集群,那这样做的最大好处就是我们流量分担开,本来呢100万的请求进来,其实可能有90万都是我们要静态资源的,只有10万才是我们服务器需要动态处理的,那有了NG4,我们把这10万放到集群里边,我们集群人呢慢慢处理,可以在一定程度上保护我们整个后台集群,再加上我们现在呢,也有一个恶意请求拦截机制,那虽然没有在网关层来做,但是秒杀服务里边有一个登录拦截器,你所有想要来秒杀的这个请求,你没有登录,我们就直接给你打回去了,这样的最大好处就是我们秒杀业务,即使我们现在设计的很快,也要二十来毫秒,但是呢,在这20毫秒你在花费之前,如果登录这个拦截器你都没通过,连这20毫秒都不用花费,可能两三毫秒就直接给你返回错误数据了。
02:45
那这样做呢,我们这个方法又会很快,无论是真正的秒杀业务逻辑20毫秒,还是你是没登录的非法的,我们给你打回去的两毫秒,我们都来保证我们的方法很快,那么就在单位时间内,一秒的单位时间内,我们这一个现成的资源就能处理,如果是错误,我们就能处理500个,那如果是正确,那一秒那就能处理50个,这样我们并发500个线程同时处理,我们就是几万的并发量,我们通同量就能上去了,那也加了恶意请求拦截,那流量错分我们没有添加,但是我们后来添加了一个队列的消峰机制,那么现在呢,即使你秒杀成功,一切核验都来通过,那想要秒杀呢,我们就得创建订单,如果我们做我们以前的业务,我们慢慢的去来调用订单方法,假设花个两三秒时间,我们花个两秒吧,或者快一点我们花个一秒,那这样的话呢,我们说在高并发里边太慢了,那怎么办?我们直接让创进单,我们发成一。
03:45
的消息,只要你秒杀成功,我们给订单的消息队列来发一个消息,后台的订单服务慢慢的来消费这个消息,那有能力的人拿到消息慢慢执行,拿到消息慢慢执行,他们都是一个一个去执行的,所以呢,我们相当于就又加断了我们的吞吐量,因为发消息他很快,我们如果是发消息,整个流程执行下来可能20毫秒,我们单位时间又能执行50个请求,但是如果是我们。
04:12
正常的调用,我们远程调用订单的创订单方法,我们需要一秒那单位时间,我们只能处理一个请求,所以我们整个吞吐量那就是一个50倍的提升。那么以前加的这些所有手段们可能呢,大多都是为了快,那动静分离,首先流量分担我们有一部分不处理,那我们处理的全部进来,要么使用缓存,要么使用队列,我们都给它加速处理。那一加速处理以后呢,我们的吞吐量全都上去了,但无论说怎么上,我们现在保证了我们高并发的快,但你再能保证快,你还得保证一个东西叫稳,那么这个快现在达到了,但是我们再快,我们都有一个极限值,我们现在呢,假设单击下我们现在这个秒杀能每秒处理1万个单,这都已经是超高的处理能力了,但是面对我们这种情况,比如秒杀服务我只上了五台,或者我五台五台上这儿还有两三台给掉线了,那就剩了两台了,但是呢。
05:12
秒杀请求网关呢,直接给我们放过来,放了10万的正常请求全部放进来,那我们这两个服务器呢,就处理不过来,他的顶峰值是1万,那接下来剩下的几万过来都得在这排队,排着排着排着排着我们就造成了请求的时间累积,第一个处理不完,第二个又在这儿等着了,第三个又等着了,第四个又等着了,那等等着等着时间一长,我们资源耗尽,我们整个服务器又要崩溃。所我们快保证了以后,我们就来保证稳,那如何保证稳,那就是在我们分布式系统里边的限流、熔断降级,我们无论哪个分布式系统,它是高并发的也好,不是高并发的也好,我们一定都要考虑我们这些因素,因为有了我们这些的保护手段以后,我们的整个集群就能达到一个字叫稳。那我们以前呢,做这个熔断降级,包括部分的限流功能,当然如果用过spring cloud的话,我们以前是用hascent trickx,我们是用cloud集成的Netflix这个公司的trick。
06:13
当然我们这个HY呢,它又不去更新了,包括它支持的功能呢,也是有限的,所以我们后来我们再来在我们的这个系统里边,我们引入s cloud,阿里巴巴,也就是阿里巴巴给我们提供的sentel,我们来完成整个系统的限流、熔断、降级工作,来把我们整个系统保护的非常稳,即使我们整个这个大集群,大集群里边有百台机器,我们有了我们sel的保护,我们这百台机器那就是一个铁打的阵营,两台两三台机器炸了,五六台炸了,或者是一台炸了,我们都没问题,我们最终就会形成类似于我们兵法里边说的铁打的阵营,流水的兵,那随便我们这些服务器炸上几个,再上线几个我都没问题,那有了我们S保护,我们就能做到们的稳,那S该怎么用呢?我们先来给大家介绍一下,打开我们给大家的这个课件,Spring cloud这个组件在分布式的基础片里边有,包括我们高级片。
07:14
里边我们这个课件呢,也发给大家,在这一块spring cloud,阿里巴巴这一系列的组件里边,我已经学了好多cloud,阿里巴巴的这个NAS,我们作为注册中心的,包括我们使用西塔,后边的这个西塔我们来演示做分布式事务的。以及我们对象存储,我们也来拿过来使用的。我们现在呢,再来使用我们将要使用的阿里巴巴的最后一个套件S呢,它呢就可以从我们限流、熔断、降级这个角度来保护我们整个系统,那么来用它的话,我们先来回顾一下什么叫熔断降级、限流,这里我们在基础片的核心概念也都说过,我们再来看一下熔断,这熔断这就跟我们电路里边的保险丝短路的保护一样,那熔断的机制就是这样,比如我们这个A服务,那像微服务呢,想要调用B服务的一个功能。
08:08
当然我们B服务呢,可能会由于各种问题,比如网络不稳定,它掉的慢了,或者我们这个方法呢,本身慢了,我们这个本身原来连数据库挺快的,数据库卡慢,导致我们方法慢,导致我们整个系列慢,所以我们这个B服务呢,可能慢了,或者直接B服务给宕机了,我们都不存在了,那我们要去调的话,如果是以前我们没有任何保护,我们使用粪来进行调用,粪呢总是给他来发请求,是然后呢,是一段时间以后,我发现粪呢,它其实有一个默认超时时间,比如说呢,这个三秒时间,三秒时间你的这个数据呢,给我不返回,我就认为这个服务出问题了,我们这个份呢,接口就会报错,但我们现在等不了这么久,因为这样的话就会引起我们整个调用链的累积效应,那A掉了,BB掉了,CC掉了,DD呢,现在这个方法要等三秒,那C相当于等了三秒D,那BA都得等,C那一个一等,大家都会等,等着等着全线卡死,资源不能得到释放。
09:08
不能及时释放,它的吞吐量下降,大量的请求呢,又在这儿排队,所以呢,这就形成了一个死循环,能力越不行,外边请求累积的越多。越多的请求呢,又需要越多的资源来进行分配处理,我们的机器整个呢就会卡死当机,所以我们需要加入熔断机制,A到B,如果发现B不成了,那我们以后直接把D给它断路掉,我A以后呢,调用B,我也不用去看B成了还是不成,我在短时间内直接快速给你返回失败,原来要等三秒分难才告诉你A这个B失败了,然后呢,现在等十毫秒,我们十毫秒都不用等A想要掉B以前呢,他经过他的经验知道B失败了,那就直接给他返回失败。所以熔断呢,能保护我们整个服务不受整个级联影响,一个炸了,它的整个调用链不至于长时间的在这儿卡死,另外呢,我们说的降级,降级呢,假设我们这个网站处于流量的高峰期,那么现在有超多的业务都在运行。
10:11
一些核心的业务,购物车订单等等也好,还有一些非核心的业务,比如这些注册之类的,那么现在呢,网站正在秒杀的高峰期间,大家资源不够用了,那怎么办呢?我们可以手工的让一些非核心业务,比如我的这个注册,这个注册呢,我把注册的这个服务器的注册业务我给他停掉,因为这个服务器的运行的不只有注册业务,可能还有其他业务,我们这样一停掉以后呢,就把大量的资源又腾给我们这个服务器的其他业务去来运行,所以我们说的这个就是降级,但我们把这个服务一停掉以后,那大家想想别人又要调这个服务,这个又停掉了,那么就给人得有一个返回的这个错误提示页面,特别是如果我们整个调用量要调用它的话,这个服务停掉了,那也得引入熔断以后呢,就不调它了,我直接给你返回错误。
11:04
所以这是我们说的降级,如果我们一个服务停掉了,我们手动的把它这个降级运行了,那停止服务,那就是降级运行马上停掉,以后呢,你想要调用它,我们都应该返回一个降级页面,比如说服务器当前正忙,或者此功能暂时不可用等等等等,那么说的这个熔断和降级它的异同点是什么?相同点呢?都是为了保证我们整个集群大部分服务的可用性和可靠性,防止我们这个崩溃,我们无论是调用链上你不成了,我把你直接阻断掉,我也不调你了,还是呢,我们出于考虑,我们流量呢太大了,牺牲一部分业务,你呢,别运行了。就让人家这些核心业务去来运行,我们都是为了保证我们集群的可用和可靠性们实现牺牲小我,成就我们全局的这个功能,包括呢,我们相同点都是用户最终体验到的都是某个功能不可用,因为呢,我们这个币呢,它都炸了,这个都返回是错误了,我们这个功能可能下订单我们调到这个扣库存,扣库存直接炸了,那么这个订单就下不成功了,调用链失败,或者呢直接我们这个库存服务停了,或者什么服务停了,那你的这一块系统整个用起它来,那就是一个错误页面,所以我们整个用户体验到的都是功能不可用,所以说白了,其实熔断降级就是一个事儿,这个服务我们让它不运行了,或者呢别人不调它了,但是呢,他们的不同点就是熔断呢,它是一个被调用方的故障,我们A去来调用BA,然后呢,B是由于自个儿的问题,A等不及了,A觉得它太慢了,或者他太卡了,或者他呢连不上A以后呢有经验。
12:42
那我不调你了,我直接呢想要调你,我给我快速返回,这是我们这个被调方的故障,然后触发我们整个系统的规则,但这块返回呢,那就是系统保护了,A想要调B,我们A服务的这个系统告诉这个A方法,你别调B了,B以前呢是失败的,所以呢,我们就直接返回了。
13:02
所以呢,我们熔断就是被调用方的故障触发的系统主动规则,你以后再调用它,我就直接给你返回错误,我们这个降级呢,其实有可能是我们人工做的,我们继续全局考虑,这些业务呢,全在运行,但我们现在网站顶不住了,流量高峰期了,我们人工的在后台啪啪啪关上几个业务,这样我们服务器的资源得到释放,整个请求呢又能处理起来了,所我们这个降级呢,我们一般是基于全局的考虑,我们手工的停掉一些服务,服务停止我们也称为服务的降级运行,这么说的熔断降级以及什么是限流。限流呢,在我们这个高并发系统里边,我们一定要用,因为高并发的所有请求进来,不是让每一个请求都全部达到后台集群的,因为后台集群有他的这个消费能力,所以我们在后台集群的这个消费能力限度之内,我们给他放行请求进来,这个就是限流,我们把打入整个服务的流量来做一个控制,比如我们整个集群的处理能力就是每秒。
14:06
20万或者每秒10万,或者每秒1万,那我们呢,从网关处给你放回来的请求,那就是1万,其他的一些运气不好的直接给你报个错误,你自己重置也好,怎么做也好,所以我们限流就是把我们整个入口的流量来做一个限制,保证我们服务不会被超过他的能力的流量全部压垮,只要超过他能力的流量我们就直接丢弃。你也不用去处理了,这不说的熔断降级和限流,这以上的这些功能我们sental通通都能做,而且比起我们用haricx,我们来看一下它们之间的对比,如果我们以前用这个trick,当然不知道的同学呢,大概就听一下就知道S很好就行了,好我们这个S呢,我们比如从这几个功能来做一个对比,一些官方文档里边呢,也都这么对比过,比如首先我们来说它的隔离策略,在隔离策略上呢,我们这个hycentricx,它是做线程池隔离。
15:05
当然他后来呢,也兼容了信号量隔离,而我们center呢,它是使用的信号量隔离,比如它的这个信号量隔离做的就是一个并发线程数的限流,假设我们现在有这么一个请求,那现在呢,有100个请求我们全部进来,我们要执行,他们这个系统呢,能力不足,只能执行50个,如果是hysonrics他来做的话,他默认呢,其实其实是为我们当前请求,比如叫hello,只要执行这个请求,你想要用hysons保护hyson tricks就为这个请求的执行来做一个线程池,然后呢,每一个请求过来,线程池里边分配一个线程来执行,就是针对于这个hello来说,那这样呢,哈,请求现在有50个相同的哈,进来那50个线程池。不是50个线程池,是线程池里边50个线程,你想要再进来,那不够了,我给你打回去,它是做的线程池隔离,但这种的hain来做,这种的缺点就是我现在有一个哈,我又有一个word请求,我又有一个哈哈哈请求,每一个请求呢,我们都想保护,那每一个请求都有自己的线程池,这样我们整个系统的线程池就会超多,那一超多以后呢,我们线程之间的切换也非常浪费时间,所以这是一个对系能的极大影响,那线程池可能用着用着资源都不够了。
16:20
导致我们这个服务宕机都有可能,但森的呢,他不这么做,他可以用信号量隔离,就比如假设用到我们这个分布式信号量也好,他当然没用分布式信号量,我们里边呢也有一个symbol for,我们JAVA8里边也有这个信号量simple for,那这个symbol for呢,那就跟我们用的red之前用的那个信号量都是一样的,然后呢,你只要请求一进来,我给你说限制是50,那调用我这个hello的每一个hello呢,每一个请求对应它有一个自个的信号量,自个的simple请求呢,一进来以后,我们发现50个hello全进来了,我们这个50已经消费完了,那我下一次进来的直接给你打回,我们不用为它每一个请求单独创建线程池,资源呢,不耗费我们使用信号量,直接扣减,只要一个请求执行完了,比如我们hello,现在我们限制他并发能力50,然后50个全进来,有一个执行完了,我们就给信号量再加一个一,现在又释放了一个信号量,新的请求呢又能进来了,咱们S呢,是基于。
17:20
与我们大量的考虑,我们使用了信号量,南开centr后来也做了这个信号量,那你说线程池隔离不好,它也有一个很大的优点,就是他的隔离非常彻底,因为每一个人呢,每一个请求都是用自己的线程池,自己的池子里边炸了,跟别人没有任何关系,但信号量就跑了,我们这个服务呢,只要有些人炸了,那我们整个服务呢,都出现一些问题。这是我们说的隔离策略以及熔断降级策略,门森呢支持非常多种熔断降级策略,比如按照响应时间的,你每个请求只要超过一秒了,我就认为这个不行了,我就不要了,包括异常比率的,我们出现的请求异常,我发了100个请求,90%都出现了异常了,那以后我就不给你发了,包括我们这个异常数,100个请求里边有五个出现异常了,我都不给你发了。所以我们可以有非常多的策略来限制我们要不要熔断和降级后边的这个调用量,后边的服务。
18:18
M这个呢,它就支持的比较少,它支持了一个基于异常比率的,包括他们的实时统计都是基于滑动窗口等等,那包括支持我们这个动态规则配置,因为现在的这些无论是降级策略也好,熔断这些策略也好,你是要基于什么的东西,这些呢都应该做成动态可配的,那这两个呢,都来可以使用数据源来做动态配置,想要把这个配置呢,能持久化保存起来,比如都保存到MYSQ这个服务,下一次启动还能用它以前的这个配置,所以这一点呢,两个都一样,但是在扩展性方面。我们这个HY呢,它是用插件的方式,而这个C呢,它是使用插槽的方式,这个插槽其实就是多个扩展点,注解呢大家都支持,我们以前如果用过HYS,我们有一个注解叫hyric command,我们这个hyric的这个命令,而我们这个sel也有这个注解,能快速的熔断保护,就是我们的sental resource来定义一个需要保护的资源,那后来还会说包括限流机制,限流呢们这斯只做了一个有限功能的支持,而我们S在限流这一块呢,就做的非常专业了,它不仅支持基于QPS的。
19:29
就是每秒请求速率的,每秒请求数的,还支持我们基于调用链关系的整个限流,而且呢,在限流方面它也做了非常多,我们对流量呢还能做整形处理,而就不行了,比如它支持非常多种流量整形模式,我们后来会说,而且呢还支持我们系统的自适应保护,我们这系统的能力他知道以后,那在低峰期给你流量都放进来,高峰期我给你限制上一些,就是自适应保护,而我们这个ha呢,它就不支持了,它就是一个比较固定,包括我们的可视化界面控制台。
20:01
我们的sentel它的整个控制台呢非常完善,而且在控制台里边都能配置一些规则,还能查看一些监控指标,各种信息我们都有,而我们herics的控制台大家以前呢可能也都见过,他呢就非常简单,就一个统计图表数据就完事了,所以对比起来呢,我们后来肯定还是使用我们的center呢,用的比较多,那下一节课我们就对呢来做一个完整的介绍使用。
我来说两句