《SpringCloud Alibaba 微服务架构》专题(十三)-Spring Cloud Alibaba之Sentinel服务降级

1.引言

除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用别的模块,可能是另外的一个远程服务、数据库,或者第三方 API 等。例如,支付的时候,可能需要远程调用银联提供的 API;查询某个商品的价格,可能需要进行数据库查询。然而,这个被依赖服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会产生堆积,最终可能耗尽业务自身的线程池,服务本身也变得不可用。
在这里插入图片描述
现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。

因此我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。

2.熔断策略

  • 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
  • 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
  • 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。
注意:以上是针对 Sentinel 1.8.0 及以上版本。1.8.0 版本对熔断降级特性进行了全新的改进升级,由于我们使用的是1.7.0版本,所以可能稍微有一点点区别,比如1.7.0版本RT策略最小请求数目不支持设置,默认为5个请求等,这些在新版本都可以进行设置,更加灵活。

Sentinel熔断降级会在调用链路中某个资源出现不稳当状态时(例如调用超时或者异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其他的资源而导致级联错误。

当资源被降级后, 在接下来的降级时间窗口之内,对该资源的调用都会自动熔断(默认行为是抛出DegradeException)。

3.熔断降级策略之RT

【a】业务层新增如下方法

package com.bruce.controller;

import com.bruce.service.SentinelService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
public class SentinelController1 {
    
    

    @GetMapping("/testRt")
    public String testRt() {
    
    
        System.out.println("请求....");
        try {
    
    
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        return "testRt..";
    }
}

【b】新增Sentinel降级规则,具体配置如下图:
在这里插入图片描述
如上配置表示:/testRt这个资源在200毫秒之内处理完成,说明没问题,否则处理不完的话,在接下来的时间窗口(这里是1秒钟)之内该资源不允许访问,会被Sentinel限制。

【c】Jmeter压力测试
在这里插入图片描述
在这里插入图片描述
当我们Jmeter点击开始后,一秒内将会发出100个/testRt请求,很明显,已经达不到200毫秒之内处理完一次请求,此时我们浏览器访问:http://localhost:8401/testRt
在这里插入图片描述
可见,此时断路器已经打开,微服务对外不可用了,当我们停止Jmeter后,再次访问:http://localhost:8401/testRt
在这里插入图片描述
可以看到,断路器开关关掉,保险丝恢复正常,我们的微服务也就恢复正常访问了。

【d】小总结

永远一秒钟打进来10个线程(大于官网要求的5个请求)调用/testRt,我们希望是200毫秒处理完本次请求任务,如果超过200毫秒还没处理完,在未来一秒的时间窗口内,断路器打开(保险丝跳闸),微服务不可用,保险丝跳闸断电了。

后面我们停止Jmeter,没有这么大的访问量了,断路器关闭(保险丝恢复),微服务恢复正常。

4.熔断降级策略之异常比例

【a】业务层新增如下方法

@GetMapping("/testExceptionRate")
 public String testExceptionRate() {
    
    
     String string = null;
     logger.info(string.toString());
     return "testExceptionRate..";
 }

【b】新增Sentinel降级规则,具体配置如下图:
在这里插入图片描述
如上配置表示:

【c】Jmeter压力测试
在这里插入图片描述
当我们启动线程组运行的时候,这里我们修改为一秒钟发送十个请求:
在这里插入图片描述
我们浏览器访问:http://localhost:8401/testExceptionRate
在这里插入图片描述
可以看到,当我们不断请求/testExceptionRate资源时,因为我们后台每次运行都直接会抛出异常,所以异常率是100%,肯定大于我们配置的0.2(20%),所以此时断路器是打开的,接口不可用。

但当我们停止Jmeter压测时,继续访问多次:http://localhost:8401/testExceptionRate
在这里插入图片描述
可以看到,当我们一秒钟之内没有发送超过5个请求时,不管异常率是多少,断路器都不会自动打开,而是直接抛出异常信息。

【d】小总结

熔断降级策略设置为异常比例的话,如果在一秒内的请求数量大于等于5,并且业务出现异常的比例大于我们设置的阈值时,那么在我们设置的时间窗口期内,断路器将会被打开,服务不可用。

5.熔断降级策略之异常数

【a】业务层新增如下测试方法

 @GetMapping("/testExceptionCount")
 public String testExceptionCount() {
    
    
     int i = 10 / 0;
     return "testExceptionRate..";
 }

【b】Sentinel策略配置,具体配置如下图:
在这里插入图片描述
http://localhost:8401/testExceptionCount,第一次访问绝对报错,因为除数肯定不能为零,我们看到页面直接展示报错信息,但是达到5次报错后,服务进入熔断后降级,断路器被打开,微服务不可用。

【c】测试

我们在浏览器访问五次:http://localhost:8401/testExceptionCount,可以看到直接抛出异常。
在这里插入图片描述
此时断路器并没有打开,但是当我们第六次访问:http://localhost:8401/testExceptionCount时,由于违反了我们配置的异常数量为5的上限,所以第六次访问开始,此时断路器自动打开,接口不可用,如下图所示:
在这里插入图片描述
【d】小总结

熔断降级策略如果设置为异常数量的话,那么当程序异常数量达到我们设置的阈值时,断路器自动打开,微服务不可用。注意,异常数量时分钟级别的。

猜你喜欢

转载自blog.csdn.net/BruceLiu_code/article/details/113886830