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
相关产品推荐
相关产品推荐

