降级规则
概念
除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。由于调用关系的复杂性,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积。Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断 (默认行为是抛出 DegradeException )
降级策略
平均响应时间 (DEGRADE_GRADE_RT):当 1s 内持续进入 5 个请求,对应时刻的平均响应时间(秒级)均超过阈值(count,以 ms 为单位),那么在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地熔断(抛出 DegradeException)。注意 Sentinel 默认统计的 RT 上限是 4900 ms,超出此阈值的都会算作 4900 ms,若需要变更此上限可以通过启动配置项 -Dcsp.sentinel.statistic.max.rt=xxx 来配置。
异常比例 (DEGRADE_GRADE_EXCEPTION_RATIO):当资源的每秒请求量 >= 5(可配置),并且每秒异常总数占通过量的比值超过阈值(DegradeRule 中的 count)之后,资源进入降级状态,即在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
异常数 (DEGRADE_GRADE_EXCEPTION_COUNT):当资源近 1 分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若 timeWindow 小于 60s,则结束熔断状态后仍可能再进入熔断状态。
平均响应时间(RT)
RT(Response Time) 超出阈值 且 时间窗口内通过的请求 >= 5,条件满足后触发降级
窗口期过后关闭断路器
RT最大为4900(若需要变更此上限可以通过配置 -Dcsp.sentinel.statistic.max.rt=xxx)
@RestController
public class SentinelController {
@GetMapping("/testC")
public String testC(){
try {
//让线程睡眠1s 使得超出阈值无法完成任务
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Sentinel testC run";
}
}
按上述配置:无限循环1s进入十个线程已经大于RT所能容忍的最大值5个了,并且设置了500ms内需要完成任务,但又在controller中让线程睡眠1s导致无法完成任务,所以一定会触发断路器即降级。在不使用Jmeter测试时可以正常访问,但使用了Jmeter后页面就限流了。
异常比例(秒级)
QPS >= 5 且 异常比例超过阈值时触发降级,时间窗口期后关闭降级。
@RestController
public class SentinelController {
@GetMapping("/testD")
public String testD(){
int i = 1 / 0;//这里故意让后端程序报错导致异常
return "Sentinel testD run";
}
}
当我们进行了以上配置并且启动了Jmeter时会报下面图1的降级错误,这是因为导致了两个条件:第一个请求数>=5,第二个错误率大于50%。当我们的第一个条件未满足即没有使用Jmeter测试,会报下面图2的后端error错误。
异常数(分钟级)
异常数超过阈值时触发降级,时间窗口期后关闭降级。
作者本人做这个是测试得比较久的,有以下两种情况。
第一种:时间窗口期 < 60的情况下
这个异常数并不是一分钟内的错误次数,这个是每秒钟的错误次数。然后经过5s后会没有降级规则。但是只要恢复error那个界面时,只要错一次,那么下一次就还是触发降级规则,并不会再根据异常数去指定规则。
第二种:时间窗口期 > 60的情况下
这个就很正常。一如既往的每秒错误次数达到2就触发熔断。然后65s后恢复。一直有这个降级规则在的。那么这两种情况的问题就在于:异常数是按分钟来计算的,所以只要时间窗口期在1分钟多就一直有这个规则,但是如果没有一分钟,就只会触发这一次规则,后面就是错一次降级一次。