SpringCloud Alibaba Sentinel 熔断降级 - 程序配制方式实现

Posted 小毕超

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud Alibaba Sentinel 熔断降级 - 程序配制方式实现相关的知识,希望对你有一定的参考价值。

一、Sentinel

上篇文章我们讲解了Sentinel 流控规则的配制,本篇文章我们继续讲下Sentinel 的熔断降级,依然采用程序配制方式实现。

上篇文章地址:https://blog.csdn.net/qq_43692950/article/details/122159806

由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。这个问题和 Hystrix 里面描述的问题是一样的。

Sentinel 和 Hystrix 的原则是一致的: 当调用链路中某个资源出现不稳定,例如,表现为 timeout,异常比例升高的时候,则对这个资源的调用进行限制,并让请求快速失败,避免影响到其它的资源,最终产生雪崩的效果。

二、Sentinel 熔断降级

Sentinel 提供了基于异常比例、异常数、慢调用比例的策略,下面来看下实现:

基于异常比例的熔断策略

新建熔断规则了:

@PostConstruct
public void initDegrade() 
    DegradeRule rule = new DegradeRule();
    rule.setResource("errdegrade");
    rule.setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType()); //熔断策略,异常比例
    rule.setCount(0.5d); //异常比例的阈值
    rule.setStatIntervalMs(10000); //统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入)
    rule.setMinRequestAmount(4); //熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入)
    rule.setTimeWindow(5); //熔断时长,单位为 s

    List<DegradeRule> rules = new ArrayList<>();
    rules.add(rule);
    DegradeRuleManager.loadRules(rules);

上面实现了基于异常比例的熔断规则,在统计时长10秒的时间,请求数达到4次,如果有50%的请求异常,则进入熔断状态,下面的请求全都进入降级方法,熔断时间为5秒,每5秒则释放一个请求测试接口是否恢复正常,如果接口恢复正常则停止熔断。

下面在编写测试接口前,先创建个全局的降级回调方法。

public class CustomerBlockHandler 
    public static ResponseTemplate blockHandler(BlockException exception) 
        return ResFailTemplate.builder().code(406).message("接口限流!").build();
    

    public static ResponseTemplate fallback() 
        return ResFailTemplate.builder().code(406).message("服务降级!").build();
    

下面编写测试接口:

@RestController
@RequestMapping("/circuitBreaker")
public class CircuitBreakerController 

    @SentinelResource(value = "errdegrade",
            blockHandlerClass = CustomerBlockHandler.class,
            blockHandler = "blockHandler",
            fallbackClass = CustomerBlockHandler.class,
            fallback = "fallback")
    @GetMapping("/errdegrade")
    public ResponseTemplate errdegrade() throws InterruptedException 
    	System.out.println("请求了!");
        int a = 1 / 0;
        return ResSuccessTemplate.builder().build();
    

下面编写测试请求程序:

@Slf4j
public class TestDegrade 
    public static void main(String[] args) throws InterruptedException 
        RestTemplate restTemplate = new RestTemplate();

        String url = "http://localhost:8080/circuitBreaker/errdegrade";
        for (int i = 1; i <= 20; i++) 
            long t = System.currentTimeMillis();
            String forObject = restTemplate.getForObject(url, String.class);
            log.info("请求次数: , 返回结果: , 耗时:", i, forObject, (System.currentTimeMillis() - t));
            Thread.sleep(500);
        
    

调用测试程序,查看打印日志:


可以看出大部分请求都已经被熔断直接进入了降级方法。

基于异常数的熔断策略

修改下上面的规则:

@PostConstruct
public void initDegrade() 
	DegradeRule rule = new DegradeRule();
	rule.setResource("errdegrade");
	rule.setGrade(CircuitBreakerStrategy.ERROR_COUNT.getType()); //熔断策略,异常数
	rule.setCount(2d); //异常数阈值
	rule.setStatIntervalMs(10000); //统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入)
	rule.setMinRequestAmount(4); //熔断触发的最小请求数,请求数小于该值时即使异常数超出阈值也不会熔断(1.7.0 引入)
	rule.setTimeWindow(5); //熔断时长,单位为 s
	
	List<DegradeRule> rules = new ArrayList<>();
	rules.add(rule);
	DegradeRuleManager.loadRules(rules);

上面的规则表示,在统计时长10秒的时间内,请求数达到4次,并且有2次错误请求,即进入熔断状态,5秒后尝试释放一个请求探测接口是否正常,如果正常则结束熔断。

还是使用上面的测试程序进行测试:



可见至进来了5个请求,其余均被熔断。

基于慢调用比例的熔断策略

修改熔断规则:

@PostConstruct
public void initDegrade() 
	DegradeRule rule = new DegradeRule();
	rule.setResource("errdegrade");
	rule.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType()); //熔断策略,慢调用比例
	rule.setCount(1500d); //慢调用临界 RT(超出该值计为慢调用)
	rule.setStatIntervalMs(10000); //统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入)
	rule.setMinRequestAmount(4); //熔断触发的最小请求数,请求数小于该值时即使异常数超出阈值也不会熔断(1.7.0 引入)
	rule.setTimeWindow(5); //熔断时长,单位为 s
	rule.setSlowRatioThreshold(0.5d); //慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)
	
	List<DegradeRule> rules = new ArrayList<>();
	rules.add(rule);
	DegradeRuleManager.loadRules(rules);

上面规则表示的意思,在10秒的时间,请求数达到了4次,并且有50%的接口处理时间超过了1.5秒的时间,则进入熔断状态,每隔5面释放一个请求用来探测接口是否已正常。

下面修改测试接口:

@RestController
@RequestMapping("/circuitBreaker")
public class CircuitBreakerController 

    @SentinelResource(value = "errdegrade",
            blockHandlerClass = CustomerBlockHandler.class,
            blockHandler = "blockHandler",
            fallbackClass = CustomerBlockHandler.class,
            fallback = "fallback")
    @GetMapping("/errdegrade")
    public ResponseTemplate errdegrade() throws InterruptedException 
        TimeUnit.SECONDS.sleep(2);
        System.out.println("请求了!");
        return ResSuccessTemplate.builder().build();
    


再次使用上面写的测试程序进行测试:


同样实现了熔断的效果。

三、熔断监听

Sentinel他还提供了熔断状态切换的监听,可以做一些自定义的逻辑:

@PostConstruct
public void ruleObserver() 
    EventObserverRegistry.getInstance().addStateChangeObserver("logging",
            (prevState, newState, thatRule, snapshotValue) -> 
                log.info(" 熔断状态改变,当前状态: ", thatRule.getResource(), newState);
            );


喜欢的小伙伴可以关注我的个人微信公众号,获取更多学习资料!

以上是关于SpringCloud Alibaba Sentinel 熔断降级 - 程序配制方式实现的主要内容,如果未能解决你的问题,请参考以下文章

SpringCloud整合Alibaba环境搭建

SpringCloud整合Alibaba环境搭建

SpringCloud整合Alibaba环境搭建

SpringCloud整合Alibaba环境搭建

SpringCloud Alibaba组件

SpringCloud Alibaba Sentinel实现熔断与限流