Sentinel规则之熔断降级规则

Sentinel规则之熔断降级规则


博客导航带你有序的阅读和学习!


概述

除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。由于调用关系的复杂性,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积。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,则结束熔断状态后仍可能再进入熔断状态。

注意:异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。为了统计异常比例或异常数,需要通过 Tracer.trace(ex) 记录业务异常。示例:

降级演示

平均响应时间RT

初始化降级规则:

public static void main(String[] args) {
  SpringApplication.run(SentinelDegradeRuleApplication.class, args);
  initDegradeRuleForRT();
}

public static void initDegradeRuleForRT(){
    List<DegradeRule> rules = new ArrayList<> ();
    DegradeRule rule = new DegradeRule();
    //设置资源名
    rule.setResource("echo");
    //设置40毫秒
    rule.setCount(40);
    //阈值类型为平均响应时间
    rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
    //时间窗口设置为5秒
    rule.setTimeWindow(5);
    rules.add(rule);
    DegradeRuleManager.loadRules(rules);
}

程序:

@RestController
public class EchoController {
    @Autowired
    private EchoService echoService;
    @GetMapping("/echo/{str}")
    public String echo(@PathVariable String str){
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
        for (int i = 1; i <= 10; i++) {
            try {
                String echo = echoService.echo(str);
                System.out.println("第"+i+"次: echo:"+echo+" | 时间:"+dateFormat.format(new Date()));
                TimeUnit.MILLISECONDS.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return "访问成功";
    }
}

//Service
public interface EchoService {
    String echo(String str);
}

//ServiceImpl
@Service
public class EchoServiceImpl implements EchoService {
    @Override
    @SentinelResource(value = "echo",blockHandler = "handleBlockException")
    public String echo(String str) {
        try {
            TimeUnit.MILLISECONDS.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "返回值:"+str;
    }

    public String handleBlockException(String str, BlockException ex){
        return " 服务降级处理:"+str+"  异常为:"+ex.getClass().getSimpleName();
    }
}

访问:

1次: echo:返回值:123 | 时间:2019-10-23 14:13:02:8092次: echo:返回值:123 | 时间:2019-10-23 14:13:02:8593次: echo:返回值:123 | 时间:2019-10-23 14:13:02:9104次: echo:返回值:123 | 时间:2019-10-23 14:13:02:9605次: echo:返回值:123 | 时间:2019-10-23 14:13:03:0106次: echo: 服务降级处理:123  异常为:DegradeException | 时间:2019-10-23 14:13:03:0497次: echo: 服务降级处理:123  异常为:DegradeException | 时间:2019-10-23 14:13:03:0498次: echo: 服务降级处理:123  异常为:DegradeException | 时间:2019-10-23 14:13:03:0509次: echo: 服务降级处理:123  异常为:DegradeException | 时间:2019-10-23 14:13:03:05010次: echo: 服务降级处理:123  异常为:DegradeException | 时间:2019-10-23 14:13:03:050

通过程序可以看出,平均响应时间(RT)是先计算前5次的请求的平均处理时间,如果超过了预定的阈值时间(count),那么在接下来的时间范围/窗口(timeWindow)后直接进行服务降级,抛出DegradeException. 等待timeWindow过后,又会重新计算RT。

我们看一下实时监控:

在这里插入图片描述

异常比例

初始化规则:

public static void initDegradeRuleForExceptionRatio(){
    List<DegradeRule> rules = new ArrayList<>();
    DegradeRule rule = new DegradeRule();
    //资源名
    rule.setResource("echo");
    //阈值类型:异常比例
    rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);
    //阈值	
    rule.setCount(0.5);
    //时间窗口为5秒
    rule.setTimeWindow(5);
    rules.add(rule);
    DegradeRuleManager.loadRules(rules);
}

测试程序:

//controller
@RestController
public class EchoController {

    @Autowired
    private EchoService echoService;

    @GetMapping("/echo/{str}")
    public String echo(@PathVariable String str) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
        for (int i = 1; i <= 10; i++) {
            String echo = echoService.echo(str, i);
            System.out.println("第" + i + "次: echo:" + echo + " | 时间:" + 
                               dateFormat.format(new Date()));
        }
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "访问成功";
    }
}

// service
public interface EchoService {
    String echo(String str, int i);
}

//serviceImpl
/**
 * @author hao.ouYang
 * @create 2019-10-22 11:05
 */
@Service
public class EchoServiceImpl implements EchoService {

    @Override
    @SentinelResource(value = "echo",blockHandler = "handleBlockException",fallback = "fallbackFun")
    public String echo(String str,int i) {
        try {
            TimeUnit.MILLISECONDS.sleep(150);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if ( i % 2 == 1){
            throw new IRuleException();
        }
        return "返回值:"+str;
    }

    public String handleBlockException(String str,int i, BlockException ex){
        return " 服务降级处理:"+str+" 参数i:"+i+"  异常为:"+ex.getClass().getSimpleName();
    }

    public String fallbackFun(String str,int i, Throwable throwable){
        return " 服务降级处理:"+str+" 参数i:"+i+" 异常为:"+throwable.getClass().getSimpleName();
    }
}

测试结果:

在这里插入图片描述

总结:一秒内要保证访问数量超过5次,否则不会出发异常比例的服务熔断降级。比例超过预定的0.5之后就会触发降级

异常数

异常数是统计1分钟时间的内,所以当时间窗口包含在统计时间内,可能一分钟之后又会立即进入统计时间范围中 。

public static void initDegradeRuleForExceptionCount(){
    List<DegradeRule> rules = new ArrayList<>();
    DegradeRule degradeRule = new DegradeRule();
  	//设置异常数阈值
    degradeRule.setCount(5);
  	//阈值类型:异常数
    degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
  	//资源名称
    degradeRule.setResource("echo");
  	//时间窗口
    degradeRule.setTimeWindow(10);
    rules.add(degradeRule);
    DegradeRuleManager.loadRules(rules);
}

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值