西宁市网站建设_网站建设公司_jQuery_seo优化
2026/1/3 22:45:25 网站建设 项目流程

Resilience4j提供了熔断、限流、重试等一系列有助于服务稳定性的功能,Springboot项目可以非常简单的进行集成。

<dependency><groupId>io.github.resilience4j</groupId><artifactId>resilience4j-spring-boot3</artifactId><version>2.3.0</version>
</dependency>

Circuitbreaker

在你的服务访问其他某服务返回结果异常, 比如5xx, timeout,可以采用Circuitbreaker(断路器)阻止后续请求继续访问异常服务,同时设置failbackMethod进行降级处理。

断路器的实现模型是一个有限状态机,分为close,open, half-open三个状态。

image

Close: 表示断路器并没有阻断了业务逻辑(方法的执行)。
Open: 表示断路器已打开阻断了业务逻辑向下游的执行,可以指定执行failbackMethod进行降级处理。
Half_open: 表示断路器为半开半闭状态,会尝试放行个别请求向下游执行,如果执行成功则关闭断路器(Close),如果执行失败则打开断路器(Open)。

circuitbreaker的常用配置参数:

minimumNumberOfCalls: 2 #至少2次请求后进行判断
failureRateThreshold: 50f #一半请求失败触发开启断路器
slidingWindowSize: 6 #每次判断的滑动窗口大小是6
slidingWindowType: COUNT_BASED #计算方式count_based,另一个是TIME_BASED
automaticTransitionFromOpenToHalfOpenEnabled: true #自动从open转成half-open
waitDurationInOpenState: 5000 #断路器在open状态的持续时间5秒
maxWaitDurationInHalfOpenState: 0 #在半开状态的等待时间0秒

example:配置一个name="sayHelloWorld"的断路器。

resilience4j:circuitbreaker:instances:sayHelloWorld:minimumNumberOfCalls: 2failureRateThreshold: 50slidingWindowSize: 6slidingWindowType: COUNT_BASEDautomaticTransitionFromOpenToHalfOpenEnabled: truewaitDurationInOpenState: 5smaxWaitDurationInHalfOpenState: 0

通过注解的方式在类或者方法上使该断路器

@CircuitBreaker(name = "sayHelloWorld")
public String sayHiNginx()  {return webClientBuilder.baseUrl("http://127.0.0.1:8083").build().get().retrieve().bodyToMono(String.class).block(); //采用WebClient的响应式模式发http请求,不用block()的情况下这种代码不work
}

这样当2次访问127.0.0.1:8083,至少1次以上不通会触发断路器。

{"status": 500,"message": "internal server error","response": "CircuitBreaker 'sayHelloWorld' is OPEN and does not permit further calls"
}

响应式编程遇到的问题
第一版写完代码进行测试的时候发现限流器根本没起作用,以为是配置的不对,后来发现代码中有1处操作导致限流器没有生效。
sayHiNginx方法想借助spring框架响应式触发http请求的结果并返回给API的调用方,但是CircuitBreaker并没有统计到http请求失败。
PS:我的测试环境里127.0.0.1:8083套接字并不存在。

@CircuitBreaker(name = "sayHelloWorld")
public Mono<String> sayHiNginx()  {return webClientBuilder.baseUrl("http://127.0.0.1:8083").build().get().retrieve().bodyToMono(String.class); //注意没有block()
}

 

@GetMapping("/smart/resilience/circuitbreaker")
public Mono<String> testCircuitBreaker() {
return resilienceService.sayHiNginx();
}

原因是项目里之前写了一个HttpRequestLogPrinterFilter类进行HttpServlet request和response的拷贝。问题出在ContentCachingResponseWrapper 与响应式类型不兼容,当 Controller 返回 Mono<String> 时,响应体是异步写入的,而 ContentCachingResponseWrapper 在 finally 中调用 copyBodyToResponse() 时,响应体可能尚未写入,导致复制为空。

public class HttpRequestLogPrinterFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);try {filterChain.doFilter(requestWrapper, responseWrapper);} finally {responseWrapper.copyBodyToResponse();}}
}

把这种异步的响应式触发改成了同步等待--加block()--http返回结果之后解决问题,但WebClient作为为响应式编程设计的httpclient,线程比较少,block()操作会占用一个珍贵的线程,这样做显然不是一个好方案。
好在resilience4j也支持了响应式编程,添加依赖:

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

初始化一个circuitBreaker bean

@Configuration
public class ResilienceConfig {@Bean(name="circuitBreaker")public CircuitBreaker initCircuitBreaker(CircuitBreakerRegistry cbRegistry) {return cbRegistry.circuitBreaker("sayHelloWorld");}
}


修改sayHiNginx方法,在末尾用transform方法把响应流转换成另一个响应流并加上CircuitBreakerOperator方法。CircuitBreakerOperator方法天然的支持reactor模式,主要实现一个UnaryOperator的apply方法应用熔断器。

@CircuitBreaker(name = "sayHelloWorld")
public Mono<String> sayHiNginx()  {return webClientBuilder.baseUrl("http://127.0.0.1:8083").build().get().retrieve().bodyToMono(String.class).transform(CircuitBreakerOperator.of(circuitBreaker));
}

这样在control层直接返回Mono对象时,spring就能成功触发熔断器的执行了。

@GetMapping("/smart/resilience/circuitbreaker")
public Mono<String> testCircuitBreaker() {return resilienceService.sayHiNginx();
}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询