You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Cloud Gateway集成Resilience4J断路器无法进入打开状态

Resilience4J与Spring Cloud Gateway集成:断路器未触发打开状态问题

在Resilience4J与Spring Cloud Gateway集成场景下,重试功能正常,但断路器始终无法进入打开状态,尽管监控已统计到失败请求,且失败率显示为-1。

配置代码

@Bean
public Customizer<ReactiveResilience4JCircuitBreakerFactory> defaultCustomizer() {
    return factory->factory.configureDefault(id->new Resilience4JConfigBuilder(id)
            .circuitBreakerConfig(CircuitBreakerConfig.custom()
                    .slidingWindowSize(5)
                    .failureRateThreshold(2)
                    .permittedNumberOfCallsInHalfOpenState(5)
                    .slowCallDurationThreshold(Duration.ofMillis(200))
                    .slowCallRateThreshold(50.0F)
                    .waitDurationInOpenState(Duration.ofSeconds(30))
                    .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.COUNT_BASED)
                    .build())
            .timeLimiterConfig(TimeLimiterConfig.custom()
                    .timeoutDuration(Duration.ofSeconds(3000))
                    .cancelRunningFuture(true)
                    .build())

            .build());
}

路由配置代码

private Buildable<Route> setPredicateSpec(ApiRoute apiRoute, PredicateSpec predicateSpec) {
    BooleanSpec booleanSpec=predicateSpec.path(apiRoute.getPath());
    booleanSpec.filters(f->
    {
        f.circuitBreaker(c->{
            c.setName("DDDDDDTTTTT");
            c.addStatusCode("500");

        });

        f.fallbackHeaders(config ->{
            config.setExecutionExceptionMessageHeaderName("message-header");
            config.setExecutionExceptionTypeHeaderName("type-header");
            config.setRootCauseExceptionMessageHeaderName("root-cause-message-header");
            config.setRootCauseExceptionTypeHeaderName("root-cause-type-header");
        });
        f.filter(authenticationFilter);
        f.retry(config->{
            config.setMethods(HttpMethod.GET);
            config.setRetries(2);
            config.setBackoff(Duration.ofMillis(50),Duration.ofMillis(500),0,false);
            config.setStatuses(HttpStatus.INTERNAL_SERVER_ERROR);
        });

        f.requestRateLimiter(r->{
            r.setKeyResolver(apiKeyResolver);
            r.setRateLimiter(rateLimiter);
        });

        return f;
    });

    if (!StringUtils.isEmpty(apiRoute.getMethod())) {
        booleanSpec.and()
                .method(apiRoute.getMethod());
    }
    return booleanSpec.uri(apiRoute.getUri());
}

当前现象

  • 失败请求已被监控统计
  • 断路器失败率显示为-1
  • 断路器未按配置进入打开状态

相关配置属性

spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key=false
management.endpoint.gateway.enabled=true
management.endpoint.health.show-details=always
management.health.circuitbreakers.enabled=true
management.endpoints.web.exposure.include=health
management.endpoint.metrics.enabled=true
management.endpoints.web.exposure.include=*
management.endpoint.prometheus.enabled=true
management.metrics.export.prometheus.enabled=true
spring.cloud.circuitbreaker.resilience4j.enabled=true

依赖配置

implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc'
implementation 'org.springframework.boot:spring-boot-starter-data-redis-reactive'
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
implementation 'org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.springdoc:springdoc-openapi-webflux-ui:1.6.11'
implementation 'io.jsonwebtoken:jjwt:0.9.1'
implementation 'javax.xml.bind:jaxb-api:2.3.1'
implementation 'org.mapstruct:mapstruct:1.5.2.Final'
annotationProcessor 'org.projectlombok:lombok'
runtimeOnly "io.opentelemetry.javaagent:opentelemetry-javaagent:1.18.0"
runtimeOnly 'io.micrometer:micrometer-core'
runtimeOnly 'io.micrometer:micrometer-registry-prometheus'

排查分析与解决方案

1. 修正断路器配置的实例匹配与阈值设置

当前自定义配置使用configureDefault,但路由中指定了具体的断路器名称DDDDDDTTTTT,默认配置可能未被正确应用到该实例。同时failureRateThreshold(2)表示仅2%的失败率阈值,几乎无法触发断路器打开,需调整为合理值(如20)。

修改配置类:

@Bean
public Customizer<ReactiveResilience4JCircuitBreakerFactory> defaultCustomizer() {
    return factory -> {
        // 为指定名称的断路器加载自定义配置
        factory.configure(builder -> builder
                .circuitBreakerConfig(CircuitBreakerConfig.custom()
                        .slidingWindowSize(5)
                        .failureRateThreshold(20) // 调整为20%的失败率阈值
                        .permittedNumberOfCallsInHalfOpenState(5)
                        .slowCallDurationThreshold(Duration.ofMillis(200))
                        .slowCallRateThreshold(50.0F)
                        .waitDurationInOpenState(Duration.ofSeconds(30))
                        .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.COUNT_BASED)
                        .build())
                .timeLimiterConfig(TimeLimiterConfig.custom()
                        .timeoutDuration(Duration.ofSeconds(3)) // 修正超时配置为3秒,原3000秒不合理
                        .cancelRunningFuture(true)
                        .build())
                .build(), "DDDDDDTTTTT");
        
        // 保留默认配置供其他断路器使用
        factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
                .circuitBreakerConfig(CircuitBreakerConfig.ofDefaults())
                .timeLimiterConfig(TimeLimiterConfig.ofDefaults())
                .build());
    };
}

2. 调整过滤器执行顺序

当前路由中重试过滤器在断路器之后添加,导致重试请求被重复统计,且断路器无法正确感知最终的调用结果。需将重试过滤器放在断路器之前,让断路器包裹整个重试逻辑:

修改路由配置的过滤器顺序:

booleanSpec.filters(f -> {
    // 先添加重试过滤器
    f.retry(config -> {
        config.setMethods(HttpMethod.GET);
        config.setRetries(2);
        config.setBackoff(Duration.ofMillis(50), Duration.ofMillis(500), 0, false);
        config.setStatuses(HttpStatus.INTERNAL_SERVER_ERROR);
    });
    
    // 再添加断路器过滤器
    f.circuitBreaker(c -> {
        c.setName("DDDDDDTTTTT");
        c.addStatusCode("500");
    });

    f.fallbackHeaders(config -> {
        config.setExecutionExceptionMessageHeaderName("message-header");
        config.setExecutionExceptionTypeHeaderName("type-header");
        config.setRootCauseExceptionMessageHeaderName("root-cause-message-header");
        config.setRootCauseExceptionTypeHeaderName("root-cause-type-header");
    });
    f.filter(authenticationFilter);

    f.requestRateLimiter(r -> {
        r.setKeyResolver(apiKeyResolver);
        r.setRateLimiter(rateLimiter);
    });

    return f;
});

3. 验证失败统计的有效性

失败率显示-1说明滑动窗口内请求数未达到配置的slidingWindowSize=5,或失败事件未被正确标记:

  • 确保调用次数至少达到5次,填满滑动窗口
  • 验证下游返回的500状态码未被其他过滤器修改
  • 添加事件监听器确认断路器是否捕获失败事件:
@Bean
public CircuitBreakerEventListener circuitBreakerEventListener() {
    return event -> {
        System.out.println("断路器事件: " + event.getEventType() + " 实例: " + event.getCircuitBreakerName());
    };
}

4. 检查依赖与版本兼容性

确保Spring Cloud与Resilience4J版本兼容,当前使用的spring-cloud-starter-circuitbreaker-reactor-resilience4j应与Spring Cloud版本匹配,避免因版本差异导致的逻辑异常。


内容的提问来源于stack exchange,提问作者mohamed hamada

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 06:45:36