resilience4j使用指南

本文介绍了如何在SpringCloud和SpringMVC环境中使用Resilience4j进行服务降级和熔断配置,包括设置熔断器的参数、配置慢请求超时、全局异常处理以及自定义的降级方法。示例涵盖了SpringCloudGateway的过滤器配置和SpringMVC的微服务熔断。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

resilience4j使用指南

1.resilience4j maven依赖

  • 当前选用的springcloud版本为3.1.6对应spring-cloud-release2021.0.6
<!--熔断降级 for spring cloud 3.1.6 @formatter:off-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
    <version>2.1.6</version>
</dependency>

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-reactor</artifactId>
    <version>1.7.0</version>
</dependency>

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-spring-boot2</artifactId>
    <version>1.7.0</version>
    <exclusions>
        <exclusion>
            <artifactId>resilience4j-bulkhead</artifactId>
            <groupId>io.github.resilience4j</groupId>
        </exclusion>
    </exclusions>
</dependency>
  • 在启动的yaml中引入resilience4j配置
#spring-cloud内置熔断组件,也支持从springboot中集成
resilience4j.circuitbreaker:
  configs:
    #熔断机制的默认设置
    default:
      #状态收集器类型
      #COUNT_BASED:根据数量计算,slidingWindowSize为次数
      #TIME_BASED:根据时间计算,slidingWindowSize为秒数
      slidingWindowType: TIME_BASED
      #时间窗口的大小为60秒
      slidingWindowSize: 600
      #在单位时间窗口内最少需要多少次调用才能开始进行统计计算
      minimumNumberOfCalls: 2
      #进入halfOpen状态时,可以被调用次数,就算这些请求的失败率,低于设置的失败率变为close状态,否则变为open。
      permittedNumberOfCallsInHalfOpenState: 2
      #允许断路器自动由打开状态转换为半开状态
      #是否自动进入halfOpen状态,默认false-一定时间后进入halfOpen,ture-需要通过接口执行。
      automaticTransitionFromOpenToHalfOpenEnabled: false
      #断路器打开状态转换为半开状态需要等待的时间
      waitDurationInOpenState: 30s
      #在单位时间窗口内调用失败率达到50%后会启动断路器
      failureRateThreshold: 50
      #消费数据处理的缓存数据量大小
      eventConsumerBufferSize: 20
      #哪些异常都当作失败来处理(会被fallback)
      recordExceptions:
        - org.springframework.web.client.HttpServerErrorException
        - java.io.IOException
        - java.util.concurrent.TimeoutException
        - java.lang.IllegalArgumentException
      #哪些异常直接忽略(不会被fallback)
      ignoreExceptions:
        - java.lang.IllegalStateException
  #熔断备用实例
  instances:
    backendA:
      #使用默认配置
      baseConfig: default
#配置熔断的超时设置
resilience4j.timelimiter:
  configs:
    #默认的慢请求的超时设置策略
    default:
      #请求的超时时间
      timeoutDuration: 3s
      #中断异步调用
      cancelRunningFuture: true

2.springcloud-gateway引入resilience4j

  • 配置springcloud-gateway的过滤器factory:

@Slf4j
@Configuration
public class NettyCircuitBreakerConfigurer
{
    /**
     * 集成了Resilience4j过滤器
     *
     * @param circuitRegistry 服务降级熔断配置
     * @param timeRegistry    服务慢请求配置
     * @return 熔断降级的filter工厂
     */
    @Bean
    public ReactiveResilience4JCircuitBreakerFactory circuitBreakerFactory(CircuitBreakerRegistry circuitRegistry,
        TimeLimiterRegistry timeRegistry)
    {
        ReactiveResilience4JCircuitBreakerFactory factory =
            new ReactiveResilience4JCircuitBreakerFactory(circuitRegistry, timeRegistry);
        factory.configureDefault(id ->
        {
            CircuitBreakerConfig circuitConf = circuitRegistry.getDefaultConfig();
            TimeLimiterConfig timeConf = timeRegistry.getDefaultConfig();
            log.info("CircuitBreaker[{}]config:{}/{}", id, circuitConf, timeConf.getTimeoutDuration().getSeconds());
            Resilience4JConfigBuilder builder = new Resilience4JConfigBuilder(id);
            //此处仅构建了一个默认的熔断策略(还可以继续添加)
            return builder.circuitBreakerConfig(circuitConf).timeLimiterConfig(timeConf).build();
        });
        return factory;
    }
}
  • 编写对应的fallback rest服务:

@Slf4j
@RestController
public class FallbackController
{
    @ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE)
    @PostMapping("/fallback")
    public Mono<ResultCode<?>> fallback(ServerWebExchange exchange)
    {
        Exception e = exchange.getAttribute(ServerWebExchangeUtils.CIRCUITBREAKER_EXECUTION_EXCEPTION_ATTR);
        ServerWebExchange delegate = exchange;
        if (exchange instanceof ServerWebExchangeDecorator)
        {
            delegate = ((ServerWebExchangeDecorator)exchange).getDelegate();
        }
        String url = delegate.getRequest().getURI().getPath();
        ResultCode<?> resultCode = ResultCode.error(ErrCodeEnum.SERVER_ERROR.getCode());
        log.error("[{}]circuit breaker result:{},with exception:{}", url, JsonUtil.toJson(resultCode), e);
        return Mono.just(resultCode);
    }
}
  • 路由配置中添加该过滤器
    #@formatter:off
    - id: demo_auth
    uri: lb://bq-demo/
    predicates:
        - Path=/bq-demo/demo/**,/bq-demo/monitor/**,/demo/**
    #为接口设置熔断过滤器
    filters:
        - name: CircuitBreaker
        args:
            name: circuitBreaker
            fallbackUri: forward:/fallback

3.基于SpringMVC的微服务中添加resilience4j:

  • 编写配置服务
@Slf4j
@Configuration
public class CircuitBreakerConfigurer
{
    /**
     * 全局默认的策略断路器
     *
     * @param circuitRegistry 断路器注册器
     * @return 断路器
     */
    @Primary
    @Bean
    public CircuitBreaker globalCircuitBreaker(CircuitBreakerRegistry circuitRegistry)
    {
        CircuitBreakerConfig circuitBreakerConf = circuitRegistry.getDefaultConfig();
        log.info("circuit breaker config is:{}", circuitBreakerConf);
        CircuitBreaker circuitBreaker = circuitRegistry.circuitBreaker("default", circuitBreakerConf);

        circuitBreaker.getEventPublisher().onSuccess(event -> log.info("circuit breaker success:{}", event))
            .onError(event -> log.info("circuit breaker error:{}", event))
            .onIgnoredError(event -> log.info("circuit breaker ignore:{}", event))
            .onReset(event -> log.info("circuit breaker reset:{}", event))
            .onStateTransition(event -> log.info("circuit breaker transition:{}", event))
            .onCallNotPermitted(event -> log.info("circuit breaker not permitted:{}", event));

        return circuitBreaker;
    }

    /**
     * 全局默认的时间策略(慢请求)断路器
     * <p>
     *
     * @param timeRegistry 断路器注册器
     * @return 断路器
     */
    @Primary
    @Bean
    public TimeLimiter globalTimeLimiter(TimeLimiterRegistry timeRegistry)
    {
        return timeRegistry.timeLimiter("default", timeRegistry.getDefaultConfig());
    }
}

3.1 使用全局的默认异常处理机制来做服务熔断

  • 编写rest服务
    /**
     * 使用全局的服务降级实现{@link com.biuqu.boot.startup.test.handler.GlobalExceptionHandler#handle(String, Exception)}
     *
     * @param param 业务参数
     * @return 返回结果
     */
    @CircuitBreaker(name = "default")
    @ResponseBody
    @PostMapping("/test/circuit-breaker/global")
    public ResultCode<String> testCircuitBreaker(@RequestBody ResultCode<String> param)
    {
        log.error("happened illegal error:{}", param);
        try
        {
            Thread.sleep(2000);
        }
        catch (InterruptedException e)
        {
            log.error("sleep error.", e);
        }
        throw new IllegalStateException("circuit breaker illegal error.");
    }
  • 定义全局的异常熔断handler
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler
{
    @ExceptionHandler({Exception.class, RuntimeException.class, Throwable.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public ResultCode<?> handleErr(HttpServletRequest req, Exception e)
    {
        log.error("global rest[{}] exception.", req.getRequestURI(), e);
        ResultCode<?> resultCode = ResultCode.error(e.getClass().getSimpleName());
        resultCode.setMsg(e.getMessage());
        return resultCode;
    }
}

3.2 使用自定义的熔断方法

  • 通过自定义的降级方法去执行
@CircuitBreaker(name = "default", fallbackMethod = "testCustomFallback")
@ResponseBody
@PostMapping("/test/circuit-breaker/custom")
public ResultCode<String> testCircuitBreakerWithCustom(@RequestBody ResultCode<String> param)
{
    log.error("happened illegal error:{}", param);
    try
    {
        Thread.sleep(1000);
    }
    catch (InterruptedException e)
    {
        log.error("sleep error.", e);
    }
    throw new IllegalStateException("circuit breaker illegal error.");
}

private ResultCode<String> testCustomFallback(@RequestBody ResultCode<String> param, Throwable e)
{
    log.error("happened illegal error:{}", param, e);
    ResultCode<String> resultCode = ResultCode.error(e.getClass().getSimpleName());
    resultCode.setMsg(e.getMessage());
    resultCode.setData("custom circuit breaker");
    return resultCode;
}

3.3 熔断可使用于各种场景,并不限于Rest请求方法:

  • rest[RestController中]请求代码:
@ResponseBody
@PostMapping("/test/circuit-breaker/service")
public ResultCode<String> testCircuitBreakerWithService(@RequestBody ResultCode<String> param)
{
    return testService.testServiceCircuitBreaker(param);
}
  • service[Service服务中]方法,下例使用了全局默认的方法:
@CircuitBreaker(name = "default")
public ResultCode<String> testServiceCircuitBreaker(@RequestBody ResultCode<String> param)
{
    log.error("happened illegal error:{}", param);
    try
    {
        Thread.sleep(1000);
    }
    catch (InterruptedException e)
    {
        log.error("sleep error.", e);
    }
    throw new IllegalStateException("circuit breaker illegal error.");
}

3.4 熔断针对慢请求的处理方法,使用了全局默认的异常处理逻辑:

  • rest服务代码
@ResponseBody
@PostMapping("/test/circuit-breaker/service/time")
public CompletableFuture<ResultCode<String>> testTimeCircuitBreakerWithService(@RequestBody ResultCode<String> param)
{
    return testService.testTimeCircuitBreaker(param);
}
  • 服务代码
@TimeLimiter(name = "default")
public CompletableFuture<ResultCode<String>> testTimeCircuitBreaker(@RequestBody ResultCode<String> param)
{
    log.error("current time limiter:{}", param);
    Supplier<ResultCode<String>> supplier = () ->
    {
        try
        {
            Thread.sleep(2005);
        }
        catch (InterruptedException e)
        {
            log.error("sleep error.", e);
        }
        return ResultCode.ok("success.");
    };
    return CompletableFuture.supplyAsync(supplier);
}

4.resilience4j使用总结:

  • resilience4j服务降级熔断是一套较完整的方法,适用于SpringWebFlux场景(如:SpringCloud-Gateway)和SpringMvc场景;
  • 在SpringCloud-Gateway的使用过程中异常简洁,如果再加上nacos的配置能力,则随时可以在路由中更改服务降级配置;
  • 服务降级不限于Rest请求,基本上任意的方法上都可以做服务降级;
  • resilience4j服务降级注解的fallbackMethod必须写在服务中,要和服务方法的参数相同,并额外加上1个异常类参数,同时返回值也必须相同,这其实不太友好,尤其不便于添加统一的服务降级逻辑;
  • resilience4j服务降级注解的fallbackMethod不写时,默认使用全局的异常处理逻辑,这虽然比较优雅,但是必须在项目前期就要求大家必须按照统一的服务出参和入参才可以;
  • resilience4j慢请求拦截采用了函数式写法;
Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet.Applet 简单实现!~ 网页表格组件 GWT Advanced Table GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以直接在你的网页里面显示搜查的结果。 github-java-api github-java-api 是 Github 网站 API 的 Java 语言版本。 java缓存工具 SimpleCache SimpleCache 是一个简单易用的java缓存工具,用来简化缓存代码的编写,让你摆脱单调乏味的重复工作!1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. 支持混合使用redis缓存和memcached缓存。可以将列表数据缓存到redis中,其他kv结构数据继续缓存到memcached 6. 支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于【自动提示】的需要(如:Google搜索), 而开发的架构无关的公共控件, 以满足该类需求可以通过快速配置来开发。AutoTips基于搜索引擎Apache Lucene实现。AutoTips提供统一UI。 WAP浏览器 j2wap j2wap 是一个基于Java的WAP浏览器,目前处于BETA测试阶段。它支持WAP 1.2规范,除了WTLS 和WBMP。 Java注册表操作类 jared jared是一个用来操作Windows注册表的 Java 类库,你可以用来对注册表信息进行读写。 GIF动画制作工具 GiftedMotion GiftedMotion是一个很小的,免费而且易于使用图像互换格式动画是能够设计一个有趣的动画了一系列的数字图像。使用简便和直截了当,用户只需要加载的图片和调整帧您想要的,如位置,时间显示和处理方法前帧。 Java的PList类库 Blister Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端 JOpenID JOpenID是一个轻量级的OpenID 2.0 Java客户端,仅50KB+(含源代码),允许任何Web网站通过OpenID支持用户直接登录而无需注册,例如Google Account或Yahoo Account。 JActor的文件持久化组件 JFile JFile 是 JActor 的文件持久化组件,以及一个高吞吐量的可靠事务日志组件。 Google地图JSP标签库 利用Google:maps JSP标签库就能够在你的Web站点上实现GoogleMaps的所有功能而且不需要javascript或AJAX编程。它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JSEditor JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接池的性能,根据某些测试数据发现,BoneCP是最快的连接池。BoneCP很小,只有四十几K
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值