限流与熔断

191 阅读7分钟

3.4 限流算法

3.4.1 令牌桶算法

Guava限流器是基于令牌桶算法实现的。令牌桶算法是一种针对请求速度的限流算法,算法的核心就是一个令牌桶,桶内令牌数量以固定的速度增长。

每个请求都需要从桶中获取到足够多的令牌后才能被放行,否则就会被阻塞或者拒绝。

通过这样一个过程,用于只需要设定令牌生成速度,算法就可以通过令牌发放来限制请求通过的速度。

优点:流量整形和方便处理突发流量。

不足: 并发请求,存在未达到设置阈值也会被限流的情况

流量整形是指令牌桶算法通过阻塞、拒绝等手段使请求以稳定的速度通过限流器,原本不规则的流量在经过限流器后变得平滑且均匀。流量整形效果非常有利于服务端稳定运行,类似我们在高并发系统中常用的基于消息队列实现的“削峰填谷”手段,经过整形后,服务端能够以稳定的状态接收并处理请求。

突发流量是指随机出现的、短时间的流量突刺。如果严格遵循流量整形的限制,那么服务端在遇到突发流量时会突然拒绝一大波请求,在客户端有重试机制的情况下还可能导致情况进一步恶化。因此,在服务端资源充足的条件下,限流器应该具有一些“弹性”,允许服务端临时超频处理一些突发请求。

在令牌桶算法模型中,“弹性”处理突发流量是非常容易实现的,只需要给桶中生成的令牌设置一个有效期即可。有突发流量时,限流器可以使用有效期内的剩余令牌来通过更多请求,从而临时提高服务端处理效率,避免大量请求被拒绝。

采用令牌桶算法策略:单机限流、单机总限流、集群非精确限流

常见问题:QPS设置100,那么每10ms会产生一个令牌,在出现并发情况,即使1s未达到100个请求,也存在被限流的情况

详情参考:限流基本功:解密谷歌Guava限流器的设计与实现

3.4.2 固定窗口计数

基于Redis INCRBY+过期时间来实现

原理:在一定时间内,对处理的请求数进行计数,每次到达时间临界点则计数器清零。

         在一定时间间隔内,若计数器数值超限,则进行限流。

优点:实现简单,单个计数周期不会超过配置阈值

不足:在两端临界点可能出现两倍的流速,流量不均匀

应用: 集群精确限流1.0、集群限频1.0、集中式限流

3.4.3 滑动窗口

滑动窗口是是一种常用的计数算法,如下图所示,窗口大小是1s,1个窗口内分配了5个桶,每个桶的时间间隔为200ms。具体的流程:

1.首先获取到当前的时间戳,用当前的时间戳除以桶的时间间隔,获取到当前桶的索引数,一般情况下桶的数量都是有限的,会前后相连形成一个环,获取到桶的索引一般还是与桶的数量取余操作;

2.获取到具体桶的位置,需要判断当前桶的数据是否过期,所以需要计算当前桶的起始时间,然后与当前桶的起始时间对比,如果不一致,则当前桶过期,数据清空,重新计数;

3.具体到限流的判断,则是获取到最近几个连续桶的数据相加与限流阈值对比,小于则通过,否则直接拒绝。

采用滑动窗口算法使用策略:集群精确限流2.0、集群限频2.0

3.4.4 自适应限流

根据系统的负载情况(CPU使用率),自动决策请求是否通过,降级了用户的使用成本

详情参考:限流阈值很难定?赶紧试试Rhino的自适应限流!

4. 熔断降级

4.1 背景

如果请求调用链路上有一个服务出现故障,如上图的服务A出现故障,错误会随着调用链路一级一级向上传播,进而导致API出现故障,进一步导致WEB也出现故障,可能由于一个服务出问题导致业务整体不可用。

造成下游服务故障的原因有很多,比如:

  • 定时任务导致负载升高
  • 代码逻辑问题
  • 网络问题

如果没有正确处理的话,服务每次都会调用下游接口,如果是下游服务不可用,每次都会长时间的超时,导致延迟大大增加。

4.2 熔断降级&重试机制

对于这种问题,比较好的方式在依赖的服务不可用时,服务调用方通过一些技术手段,向上提供有损服务,保证业务柔性可用。

名称解释示例
强依赖用户有感知,出错会影响整体流程用户下单接口
弱依赖用户无感知,出错不会影响整体流程用户查看实时配送数据

重试机制,如果下游的的接口是核心依赖(强依赖),在出现异常的情况下,可以通过重试尽可能的保证成功率,下游服务如果没有出现大面积的异常,通过重试就可以获取到正常的响应。

熔断降级功能,如果下游的接口是弱依赖,可以监控接口每次调用的健康度,如果健康度低于设置的阈值时,自动熔断所依赖的下游服务,直接返回降级数据,保证服务可用。

4.3 熔断降级参数配置

熔断降级参数说明:Rhino 熔断降级Java接入文档

Rhino 熔断降级

5. 隔离/异步

比如某个Web服务,默认的工作线程池数量是100,此时方法A依赖的组件异常导致方法A处理的延迟增加,导致方法A占用的线程池资源会越来越多,慢慢方法A会占用所有的线程资源,导致方法B、方法C也无法对外提供服务。

5.1 动态配置

线程池的参数如何确定是一项比较困难的方式,所以我们提供了线程池动态配置的功能,支持实时的对线程池参数条中。

5.2 监控告警

与此同时,还提供了线程池运行的实时监控功能,可根据配置的告警规则,实时告警。

详解线程池原理:Java线程池实现原理及其在美团业务中的实践

7. 主动GC

对很多开发的同学来说,经常会碰到这种问题,自己负责的应用在流量高峰期突然触发FGC,出现STW,对业务造成了很大的影响。

其实公司有很多应用都有类似的问题,比如外卖相关的应用,午饭时间和晚饭时间是他们的业务高峰期,再比如打车相关的应用,早高峰和晚高峰是他们的业务高峰期。

如果应用在业务高峰期触发一次FGC,就有可能会导致应用的部分实例在短暂时间内不可用,这对高并发的业务影响很大。

参数配置详参考:怎样减少应用在业务高峰期发生FGC?

8. SOP预案

从公司COE平台的历史记录来看,有多数造成实际损失的故障响应处理时间都在10~30分钟,并且大部分故障处理流程都因为业务侧没有建立完善的应急处理机制,导致没有遵循“先止损,后排查”的流程,在5Why复盘分析中,“为什么故障持续了...时间后才恢复”成为了一个高频问题。

Rhino以SOP预案平台为基础,希望联合雷达、Monkey、COE等平台,帮助业务侧建立更加高效的应急处理机制,快速处理故障,期望能够达到止损、恢复的目的。

详情参考:Rhino SOP预案平台简介