文档参考:书名:《企业it架构转型之道》-钟华
前文如下:
19.【学习心得】学习心得-大促秒杀活动催生缓存技术的高度使用
限流和降级
什么是限流和降级?这一互联网场景下所产生的词语可能对于很多的读者还比较陌生,而这两个能力是平台在服务化体系下还能保持稳定运行所必须具备的。设想一个场景,你开发了一个企业中非常核心的一个服务,日常情况下会有上百个应用调用,如果对服务的调用不加限制的使用,可能会因为某个应用开发的bug或不合理设计对给服务造成了非常大的压力,直接导致所有服务节点全部被请求占满,使得原本非常核心的应用因为访问服务超时而产生了很大的生产事故。从现象来说,所有服务节点看起来运行都很繁忙,但从应用方的角度来看,因为服务响应时间过长,实际上该服务并没有提供有效服务。从道理来说,服务就是给其他应用提供服务的,用户怎么调用服务是很难控制的,所以必须从服务自身做好保护,否则可能因为一个小的问题而造成平台级的故障。
另一个是大促活动的场景,经过前期精心的评估和准备,基于对访问峰值的预估,准备了50台服务器来应对大促活动的到来,但大促活动开始后,让大家始料未及的是原本预估有100万人参加本次大促活动,瞬间涌来了1000万的用户,这远超过服务处理能力的访问请求,会使后端的服务器直接满负荷运算,并伴随着大量的资源抢占和上下文切换,使平台处理能力下降到一个极低的程度(通常是服务器正常运转下处理能力量级的差别),这都直接影响了业务请求的响应时间,从而造成更多的业务请求排队,最终造成整个平台无法响应和崩塌。这样类似的场景都是因为平台不具备限流的能力。
限流的作用相当于电路上的保险丝,当过载的时候掐掉一些流量,让系统有能力集中资源以较快的速度处理平台处理能力范围内的业务请求。 也就是上面大促场景中,仅让1000万用户中的100万用户进入后端的处理流程中,将其余900万用户的请求通过队列排队或直接阻挡在平台处理单元之外的方式,保障平台能在处理能力范围内对100万的用户请求进行处理。
平台要具备限流的能力,首先需要对服务部署的能力有一个准确的评估,知道服务实例的部署量到底最大能满足多少业务请求的处理要求。这就需要采用压力测试的方式对系统进行压测,但传统的压力测试方法都是采用模拟的数据,从实践的角度来看,这些压测的数据与在实际生产环境中所表现的指标还是有比较大的偏差,也就是说,采用模拟数据进行压力测试的方式并不能准确测量出平台的能力峰值。
在掌握服务的容量后,接下来就是要针对服务资源的使用情况进行监控,通过资源监控的指标与之前所获取的服务处理上限进行比较,如果超过服务处理上限则启动限流。 通过CPU、内存、磁盘IO等资源的使用情况来判断系统目前的负载往往是不准确的,因为很多情况下系统本身的处理能力处于什么样的水位跟这些操作系统资源的使用情况没有一个清晰地对应关系,所以在实际中,都会通过服务的QPS作为限流的关键判断指标。
对于平台限流的实现,先从一个典型服务化应用架构的角度来看。用户的请求首先会通过前端接入层(一般采用Nginx)分发到后端的应用集群上,应用集群中主要负责用户的前端交互以及基于业务需求对后端服务集群中的服务进行服务调用。为了避免大促秒杀场景时,远超过系统处理负载上限的访问请求,同时也能很好的兼顾安全问题,通过一些安全策略防止对平台的恶意攻击,所以最优的限流拦截点在前端接入层面(如图8-1所示),因为让访问洪流进入到系统的下层,对于系统的冲击以及限流的难度都会加大。
阿里巴巴是通过在Nginx上实现的扩展组件TMD(Taobao Missile Defense,淘宝导弹防御系统)实现了接入层限流的主要工作,TMD系统可通过域名类限流、cookie限流、黑名单以及一些安全策略等很好地实现了在接入层的限流措施。
TMD系统包含了淘宝技术团队开发的开源模块nginx-http-sysguard,主要用于当访问负载和内存达到一定的阀值之时,会执行相应的动作,比如直接返回503,504或者其他URL请求返回代码,一直等到内存或者负载回到阀值的范围内,站点恢复可用。对于nginx-http-sysguard模块的具体使用,在淘宝开放的Tengine平台上有非常详细的介绍,读者可自行到该站点(tengine.taobao.org/document_cn…
在模块nginx-http-sysguard基础上,淘宝TMD系统给用户提供了可视化的配置管理界面,方便用户针对不同的业务场景实现不同的限流规则,如图8-2所示。如果有来自单台机器持续高频率访问淘宝平台上的一个URL页面,可在TMD中设置规则:访问频率大于180次/每秒,则进行IP访问频率限速或cookie访问频率限速。正是有了TMD这样配置灵活、操作方便的规则配置界面,运维人员都可以针对所发现的异常请求以及实时的处理状态,设置出各种保护措施,保障平台在面对大促秒杀或恶意攻击时,具有一定的自我保护能力,在平台接入层外部惊涛骇浪的访问洪流下,平台接入层内部保持稳定、健康的运行状态。
服务层限流
TMD平台能很好地实现在平台接入层的限流功能,但对于服务层就无能为力了。对于实现服务的限流控制,传统的实现方式通常使用Spring的AOP机制,对需要限流的接口定义一个advice拦截器,示例代码如下:
其中的SpuServiceApiAdvice类实现MethodBeforeAdvice接口,重写before方法,那么在调用指定的接口或者方法前会计算当前线程数或QPS,如果当前的线程数大于所设置的最大线程数阈值,则返回访问限流的异常信息,示例代码如下:
这套流控技术方案是可行的,实现起来也比较简单,但在实际应用场景中还是会发现不少问题以及功能的局限性,比如:
1)如果一个应用需要对100个接口进行限流,那么对应地也就需要配置100个advice和编写100个拦截器,如果是成百上千的应用呢?
2)限流阀值是硬编码形式(一般采用static值),阀值修改繁琐,也没有统一的管理和配置。
3)在某些情况下,当前服务的处理线程池被占满,导致该问题的原因可能不是来自服务调用上游,而是因为依赖的下游服务出现异常导致的,所以单单在服务端的限流手段太过单一,需要结合服务调用上下游进行更灵活的设置。
4)缺乏统一的监控平台,对当前的服务限流情况没有全局管控。
5)限流算法简单,当在双十一这种特殊场景,会看到毛刺现象,需要一种更平滑的限流算法。
限流平台Sentinel
因为此方案在实际应用中所暴露出的问题,所以有了限流平台Sentinel的出现。Sentinel平台正如它英文的意思“哨兵”一样,为整个服务化体系的稳定运行行使着警戒任务,是对资源调用的控制平台,主要涵盖了授权、限流、降级、调用统计监控四大功能模块:
❑授权——通过配置白名单与黑名单的方式对HSF的接口和方法进行调用权限的控制;
❑限流——对特定资源进行调用的保护,防止资源的过度调用;
❑降级——判断依赖的资源的响应情况,当依赖的资源响应时间过长时进行自动降级,并且在指定的时间后自动恢复调用;
❑监控——提供了全面的运行状态监控,实时监控资源的调用情况(QPS、响应时间、限流降级等信息)。Sentinel平台有两个基础概念:资源和策略,对特定的资源采取不同的控制策略,起到保障应用稳定性的作用。Sentinel提供了多个默认切入点,比如服务调用时,数据库、缓存等资源访问时,覆盖了大部分应用场景,保证对应用的低侵入性;同时也支持硬编码或者自定义AOP的方式来支持特定的使用需求。
Sentinel平台有两个基础概念:资源和策略,对特定的资源采取不同的控制策略,起到保障应用稳定性的作用。Sentinel提供了多个默认切入点,比如服务调用时,数据库、缓存等资源访问时,覆盖了大部分应用场景,保证对应用的低侵入性;同时也支持硬编码或者自定义AOP的方式来支持特定的使用需求。
Sentinel平台的架构如图8-4所示,需要通过Sentinel实现限流功能的应用中都嵌入了Sentinel客户端,通过Sentinel客户端中提供对服务调用和各资源访问缺省实现的切入点,使得应用方完全不需要对要实现限流的服务或资源进行单独的AOP配置和实现,同时不仅可以限制自己的应用调用别的应用,也可以限制别的应用调用对用我的应用。通过这些资源埋点实时计算当前服务的QPS,也可通过现有的监控系统获取到应用所在服务器的相关系统监控指标,用于限流规则设置中的阀值比对。
Sentinel控制台(如图8-5所示)会从客户端拉取资源实时的运行监控数据(比如QPS、响应时间等),并展现在控制台的监控界面上。控制台给运维人员提供了针对服务、缓存、数据库等资源访问设置各种限流规则,并将设置好的规则发送到Diamond的规则配置中心后,再有Diamond服务器将规则推送到相关的Sentinel客户端,让设置的规则最终在应用运行状态时快速生效。
设想一下,如果在双11活动启动后,大量的用户订单请求涌入平台,此时如果发现平台的整体水位已经像平台最大处理能力的水位逼近时,除了限流可以起到第一层的保护作用外,我们还可以将那些之前标记为弱依赖的服务平滑下线,也就是让订单创建的处理流程中去掉那些弱依赖的服务调用,达到将节省出的系统资源更好地服务于核心服务的运行;又或者在大促时,某核心服务依赖了某一个非核心的服务,但发现因为这个非核心服务的处理性能和服务响应时间较长,导致了当前核心服务的处理出现了瓶颈,这时为了保证核心服务的正常处理,就需要在核心服务业务逻辑中对于那个非核心服务的调用暂时停止。这样类似的场景就称为服务降级,即从服务调用者的角度,对所依赖的下游服务采取停止调用的措施,以保证当前服务的处理效率。
要实现服务降级,需要在应用或服务实现中,首先留下可供服务降级进行服务是否调用切换的逻辑。一般在代码中采用static值的方式,作为业务逻辑分支的判断条件,通过对这些static值的修改,实现服务调用逻辑的变化。同样可以通过Sentinel控制台提供的降级规则的配置功能(如图8-6所示),当对某个服务的方法响应时间一旦超过阀值后,就意味着调用的这个服务已经出现了处理性能的问题,则会自动切换到降级模式,降级持续的时间可自定义设置。