编码技巧——Sentinel的blockHandler与fallback

这篇具有很好参考价值的文章主要介绍了编码技巧——Sentinel的blockHandler与fallback。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文介绍Sentinel的blockHandler与fallback的区别,背景是:发生限流时,配置的sentinel的blockhandler没有生效而fallback生效了;排查原因,从而给出Sentinel配置异常降级和限流降级的代码写法;

在查看源码前,查阅了相关的技术帖子(1. Sentinel的blockHandler与fallback的区别 2.Sentinel服务熔断[fallBack/blockHandler]),针对同时配置fallback和blockHandler的场景,其中的结论存在不一致,所以决定自己亲手实践下;

1. 未配置fallback和blockHandler

代码如下,仅配置SentinelResource的value,并去sentinel控制台配置单机限流为1;

限流方法:

    /**
     * 测试sentinel的降级方法
     */
    @SentinelResource(value = "testSentinelFallback")
    public String testSentinelFallback() {
        return "返回成功ok";
    }

测试代码:

    @Override
    public String mock() {
        // 异步调用 模拟并发情况
        for (int i = 0; i < 5; i++) {
            CompletableFuture.runAsync(() -> {
                try {
                    final String result = testSentinelService.testSentinelFallback();
                    log.info("调用返回结果 [result={}]", result);
                } catch (Throwable e) {
                    log.warn("调用抛出异常", e);
                }
            });
        }
        return null;
    }

sentinel后台配置:

编码技巧——Sentinel的blockHandler与fallback,代码技巧,sentinel,blockHandler,fallback,限流,降级

执行结果:

调用返回结果 [result=返回成功ok]

调用抛出异常
java.lang.reflect.UndeclaredThrowableException: null
Caused by: com.alibaba.csp.sentinel.slots.block.flow.FlowException: null

调用抛出异常
java.lang.reflect.UndeclaredThrowableException: null
Caused by: com.alibaba.csp.sentinel.slots.block.flow.FlowException: null
...

2. 仅配置blockHandler

2.1 配置blockHandler时未带上额外参数BlockException
    @SentinelResource(value = "testSentinelFallback", blockHandler = "myBlockHandler")
    public String testSentinelFallback() {
        return "返回成功ok";
    }

    public String myBlockHandler() {
        return "进入myBlockHandler逻辑";
    }

执行结果:未进入限流降级方法

调用返回结果 [result=返回成功ok]

调用抛出异常
java.lang.reflect.UndeclaredThrowableException: null
Caused by: com.alibaba.csp.sentinel.slots.block.flow.FlowException: null

调用抛出异常
java.lang.reflect.UndeclaredThrowableException: null
Caused by: com.alibaba.csp.sentinel.slots.block.flow.FlowException: null
...
2.2 正确的配置blockHandler
    @SentinelResource(value = "testSentinelFallback", blockHandler = "myBlockHandler")
    public String testSentinelFallback() {
        return "返回成功ok";
    }

    public String myBlockHandler(BlockException blockException) {
        return "进入myBlockHandler逻辑";
    }

执行结果:成功进入限流降级方法

调用返回结果 [result=返回成功ok]

调用返回结果 [result=进入myBlockHandler逻辑]

调用返回结果 [result=进入myBlockHandler逻辑]
...
2.3 blockHandler能捕获业务异常
    @SentinelResource(value = "testSentinelFallback", blockHandler = "myBlockHandler")
    public String testSentinelFallback() {
        if (Boolean.TRUE) {
            throw new BusinessException(FacadeResultCodeEnum.BAD_PARAMS);
        }
        return "返回成功ok";
    }

    public String myBlockHandler(BlockException blockException) {
        return "进入myBlockHandler逻辑";
    }

执行结果:接口被限流时,成功进入限流降级方法;接口出现业务异常时,会抛到外层

调用抛出异常
BusinessException

调用返回结果 [result=进入myBlockHandler逻辑]

调用返回结果 [result=进入myBlockHandler逻辑]
...

3. 仅配置fallback

3.1 配置fallback时未带上额外参数Throwable
    @SentinelResource(value = "testSentinelFallback", fallback = "myFallback")
    public String testSentinelFallback() {
        if (Boolean.TRUE) {
            throw new BusinessException(FacadeResultCodeEnum.BAD_PARAMS);
        }
        return "返回成功ok";
    }

    public String myFallback() {
        return "进入myFallback逻辑";
    }

执行结果:接口被限流时,或者接口出现业务异常时,都会进入fallback降级方法

调用返回结果 [result=进入myFallback逻辑]

调用返回结果 [result=进入myFallback逻辑]

调用返回结果 [result=进入myFallback逻辑]
...

3.2 配置fallback时带上额外参数Throwable

    @SentinelResource(value = "testSentinelFallback", fallback = "myFallback")
    public String testSentinelFallback() {
        if (Boolean.TRUE) {
            throw new BusinessException(FacadeResultCodeEnum.BAD_PARAMS);
        }
        return "返回成功ok";
    }

    public String myFallback(Throwable throwable) {
        if (throwable instanceof BlockException) {
            return "进入myFallback逻辑 限流异常";
        }
        return "进入myFallback逻辑 业务异常";
    }

执行结果:接口被限流时,或者接口出现业务异常时,都会进入fallback降级方法;且可以通过异常类型区分出限流异常和业务异常

调用返回结果 [result=进入myFallback逻辑 业务异常]

调用返回结果 [result=进入myFallback逻辑 限流异常]
调用返回结果 [result=进入myFallback逻辑 限流异常]
...

4. 同时配置fallback和blockHandler

    @SentinelResource(value = "testSentinelFallback", fallback = "myFallback", blockHandler = "myBlockHandler")
    public String testSentinelFallback() {
        if (Boolean.TRUE) {
            throw new BusinessException(FacadeResultCodeEnum.BAD_PARAMS);
        }
        return "返回成功ok";
    }

    public String myFallback(Throwable throwable) {
        if (throwable instanceof BlockException) {
            return "进入myFallback逻辑 限流异常";
        }
        return "进入myFallback逻辑 业务异常";
    }

    public String myBlockHandler(BlockException blockException) {
        return "进入myBlockHandler逻辑";
    }

执行结果:若blockHandler和fallback都进行了配置,在未触发限流进入到方法逻辑抛出业务异常时,会进入fallback方法在触发限流时,进入不到方法逻辑,直接抛出BlockException进入blockHandler方法

5. 结论

5.1 异常捕获逻辑

1. blockHandler

  • blockHandler仅处理限流异常;
  • 使用blockHandler时,方法签名参数与原方法一致,且必须要在参数的最后位置补充BlockException参数;
  • 若未补充BlockException参数则不生效;

2. fallback

  • fallback可以处理所有类型异常,包括限流异常和业务异常;
  • 使用fallback时,方法签名参数可以与原方法完全一致,或者也接受在参数的最后位置补充Throwable参数;
  • 通过对Throwable参数的类型区分是限流异常还是其他异常;
  • 当同时生效blockHandler和fallback时,限流异常会优先被blockHandler处理而不再进入fallback逻辑;
5.2 合理的代码写法

(1)同时配置生效blockHandler和fallback分别处理限流异常和业务异常

    @SentinelResource(value = "testSentinelFallback", fallback = "myFallback", blockHandler = "myBlockHandler")
    public String testSentinelFallback() {
        // ...
        return "返回成功ok";
    }

    public String myFallback(Throwable throwable) {
        return "进入myFallback逻辑 业务异常";
    }

    public String myBlockHandler(BlockException blockException) {
        return "进入myBlockHandler逻辑";
    }

(2)仅配置fallback并通过Throwable类型区分限流异常和业务异常

    @SentinelResource(value = "testSentinelFallback", fallback = "myFallback")
    public String testSentinelFallback() {
        // ...
        return "返回成功ok";
    }

    public String myFallback(Throwable throwable) {
        if (throwable instanceof com.alibaba.csp.sentinel.slots.block.flow.FlowException) {
            final FlowRule rule = ((FlowException) throwable).getRule();
            final double count = rule.getCount();
            final String resource = rule.getResource();
            // 打印限流规则信息
            log.warn("testSentinelFallback触发限流降级 [sentinelResource={} QpsLimit={}]]", resource, count);
            return null;
        } else {
            log.warn("testSentinelFallback触发异常降级 抛出异常", throwable);
            throw new RuntimeException("testSentinelFallback业务异常");
        }
    }
5.3 注解参数释义及注意事项

1. @SentinelResource注解参数说明

属性 默认值 说明
blockHandler

用于在抛出限流/熔断/系统保护等异常的降级处理逻辑,blockHandler 针对BlockException类型的异常,优先级比fallback高

blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException;

blockHandler 函数默认需要和原方法在同一个类中;

blockHandlerClass 若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析;
defaultFallback 默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法);

默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理;

若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效

entryType EntryType.OUT 资源调用的流量类型,是入口流量(EntryType.IN)还是出口流量(EntryType.OUT),注意系统保护规则只对 IN 生效
exceptionsToIgnore 用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出; 优先级高于exceptionsToTrace
exceptionsToTrace Throwable.class 用于指定哪些异常不被排除掉;如果属于该类型,则会计入异常统计中,也会进入 fallback 逻辑中,不会原样抛出;不建议修改默认值;
fallback

用于在抛出异常的时候提供 fallback 处理逻辑;fallback 针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)

方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常(注意和blockHandler添加的BlockException不一样)

fallbackClass 类似blockHandlerClass参数
resourceType 资源类型,默认0
value 资源名称,必需项

2. 区分限流异常和熔断异常

限流状态会抛异常:FlowException(继承BlockException)

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.alibaba.csp.sentinel.slots.block.flow.FlowException] with root cause
 
com.alibaba.csp.sentinel.slots.block.flow.FlowException: null

熔断状态会抛异常:DegradeException(继承BlockException)

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.alibaba.csp.sentinel.slots.block.degrade.DegradeException] with root cause
 
com.alibaba.csp.sentinel.slots.block.degrade.DegradeException: null

 

参考:annotation-support | Sentinel文章来源地址https://www.toymoban.com/news/detail-634271.html

到了这里,关于编码技巧——Sentinel的blockHandler与fallback的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Sentinel】Sentinel与gateway的限流算法

    线程隔离有两种方式实现: 线程池隔离(Hystrix默认采用) 信号量隔离(Sentinel默认采用) 服务I需要远程调用服务A、服务B,则创建两个线程池,分别用来处理服务I–服务A,和服务I–服务B的请求。和线程池隔离不同的是,信号量隔离比较轻量级,就维护一个计数器就好,不

    2024年02月09日
    浏览(52)
  • Sentinel dashboard的使用;Nacos保存Sentinel限流规则

    Nacos环境搭建 Nacos注册中心的使用 Nacos配置中心的使用 Sentinel 容灾中心的使用 Sentinel · alibaba/spring-cloud-alibaba Wiki · GitHub github地址:Sentinel/sentinel-dashboard at master · alibaba/Sentinel · GitHub 创建sentinel-dashboard的启动脚本,并添加如下信息: 目录: 注意:sentinel-dashboard默认会在87

    2024年02月15日
    浏览(38)
  • Sentinel 降级、限流、熔断

    在现代分布式系统中,如何有效地保护系统免受突发流量和故障的影响,是每个开发人员和架构师都需要思考的重要问题。在这样的背景下,Sentinel作为一个强大的系统保护和控制组件,为我们提供了降级、限流、熔断等多种策略,帮助我们更好地保障系统的稳定性和可用性

    2024年01月24日
    浏览(44)
  • Sentinel针对IP限流

    改造限流策略的针对来源选项 设置规则(只能填入一个限制IP,多个IP需要设置多条规则)  IP流控规则 总结:IP为127.0.0.1的请求限制为1QPS,总请求限制为3QPS,单个IP请求限制不能大于default请求限制,default默认生效。  

    2024年02月15日
    浏览(37)
  • sentinel熔断与限流

    sentinel官网地址 添加链接描述 sentinel - github地址 添加链接描述 随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、流量路由、熔断降级、系统自适应过载保护、热点流量防护等多个维度保护服务的稳定性。 Sentinel 具有以下特

    2024年02月02日
    浏览(58)
  • Sentinel限流、熔断

            sentinel 提供了两种不同的隔离机制:信号量隔离和线程池隔离,它们的主要区别如下: 信号量隔离(Semaphore Isolation) : 原理 :信号量隔离基于计数器(或称令牌桶)的概念。对某个资源设置一个并发访问的最大数量(信号量大小),当请求到达时,如果当前信

    2024年01月18日
    浏览(37)
  • Sentinel的限流和Gateway的限流差别?

    问题说明:考察对限流算法的掌握情况 限流算法常见的有三种实现:滑动时间窗口,令牌桶算法,漏桶算法。gateway则采用基于Redis实现的令牌桶算法。但是我们不会去用,而Sentinel 功能比较丰富。 而sentinel内部比较复杂: 默认限流模式是基于滑动时间窗口算法 针对资源做统

    2024年02月09日
    浏览(37)
  • Sentinel限流--流控模式与限流效果

    簇点链路就是项目内的调用链路(controller - servcie - mapper ),链路中被监控的每个接口就是一个资源。 默认情况下sentinel会监控SpringMVC的每一个端点(Endpoint),Endpoint可以理解为controller中的每一个方法,每一个端点(Endpoint)就是调用链路中的一个资源。 流控、熔断等都是

    2024年02月17日
    浏览(41)
  • Sentinel限流中间件

    目录 介绍 Sentinel 的特征 Sentinel 的组成 实战使用 简单实例 配置本地控制台 使用可视化ui配置简单流控 配置异步任务限流 使用注解定义限流资源 SpringCloud整合Sentinel 简单整合  并发线程流控 关联模式  整合openFeign使用 随着微服务的流行,服务和服务之间的稳定性变得越来越

    2024年02月15日
    浏览(36)
  • Sentinel限流规则-流控效果

    流控效果是指请求达到流控阈值时应该采取的措施,包括三种: 1.快速失败:达到阈值后,新的请求会被立即拒绝并抛出FlowException异常。是默认的处理方式。 2.warm up:预热模式,对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化,从一个较小值逐渐增加

    2024年01月19日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包