Spring Boot 微服务的完整弹性指南 — 使用所有 Resilience4j 注解
发布: (2025年12月2日 GMT+8 17:44)
4 min read
原文: Dev.to
Source: Dev.to
假设
您正在使用 Spring Boot 并集成 resilience4j-spring-boot2/resilience4j-spring-boot3(Resilience4j 1.x/2.x 的使用方式类似)。示例代码为普通的 Java + Spring(非响应式)。
Maven (pom.xml)
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot3</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-all</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Gradle (Kotlin DSL)
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("io.github.resilience4j:resilience4j-spring-boot3:1.7.1")
implementation("io.github.resilience4j:resilience4j-all:1.7.1")
implementation("io.micrometer:micrometer-registry-prometheus")
implementation("org.springframework.boot:spring-boot-starter-actuator")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("com.github.tomakehurst:wiremock-jre8:2.27.2")
}
选择与您的 Spring Boot 版本兼容的依赖版本。
application.yml – 配置示例
resilience4j:
circuitbreaker:
configs:
default:
registerHealthIndicator: true
slidingWindowType: COUNT_BASED
slidingWindowSize: 20
minimumNumberOfCalls: 10
permittedNumberOfCallsInHalfOpenState: 5
waitDurationInOpenState: 30s
failureRateThreshold: 50
automaticTransitionFromOpenToHalfOpenEnabled: false
instances:
externalServiceCB:
baseConfig: default
waitDurationInOpenState: 10s
failureRateThreshold: 40
retry:
instances:
externalServiceRetry:
maxAttempts: 3
waitDuration: 500ms
retryExceptions:
- java.io.IOException
- java.util.concurrent.TimeoutException
timelimiter:
instances:
externalServiceTL:
timeoutDuration: 2s
cancelRunningFuture: true
bulkhead:
configs:
default:
maxConcurrentCalls: 10
maxWaitDuration: 0ms # for semaphore bulkhead
threadpool-default:
maxThreadPoolSize: 10
coreThreadPoolSize: 5
queueCapacity: 50
keepAliveDuration: 30s
instances:
semaphoreBulkhead:
baseConfig: default
maxConcurrentCalls: 20
threadPoolBulkhead:
baseConfig: threadpool-default
ratelimiter:
instances:
externalServiceRateLimiter:
limitForPeriod: 10
limitRefreshPeriod: 1s
timeoutDuration: 0
management:
endpoints:
web:
exposure:
include: health,info,prometheus
endpoint:
health:
show-details: always
示例组件
ExternalClient.java – 轻量 HTTP 客户端(使用 RestTemplate)
@Service
public class ExternalClient {
private final RestTemplate restTemplate;
public ExternalClient(RestTemplateBuilder builder) {
this.restTemplate = builder
.setReadTimeout(Duration.ofSeconds(5))
.setConnectTimeout(Duration.ofSeconds(2))
.build();
}
public String getRemoteData(String id) {
String url = "https://external.service/api/resource/" + id;
return restTemplate.getForObject(url, String.class);
}
}
ResilientService.java – 应用 Resilience4j 注解
@Service
public class ResilientService {
private final ExternalClient externalClient;
public ResilientService(ExternalClient externalClient) {
this.externalClient = externalClient;
}
// RateLimiter → Semaphore Bulkhead → Retry → CircuitBreaker
@RateLimiter(name = "externalServiceRateLimiter", fallbackMethod = "rateLimiterFallback")
@Bulkhead(name = "semaphoreBulkhead", type = Bulkhead.Type.SEMAPHORE, fallbackMethod = "bulkheadFallback")
@Retry(name = "externalServiceRetry", fallbackMethod = "retryFallback")
@CircuitBreaker(name = "externalServiceCB", fallbackMethod = "circuitFallback")
public String getData(String id) {
return externalClient.getRemoteData(id);
}
// --- Fallback methods (signatures must match) ---
public String circuitFallback(String id, Throwable t) {
return "circuit-fallback: cached-or-default";
}
public String retryFallback(String id, Throwable t) {
return "retry-fallback: sorry";
}
public String bulkheadFallback(String id, BulkheadFullException ex) {
return "bulkhead-fallback: overloaded";
}
public String rateLimiterFallback(String id, RequestNotPermitted ex) {
return "rate-limited-fallback: try-later";
}
}
AsyncResilientService.java – 异步模式(TimeLimiter + 线程池 Bulkhead)
@Service
public class AsyncResilientService {
private final ExternalClient externalClient;
private final ExecutorService executor = Executors.newFixedThreadPool(10);
public AsyncResilientService(ExternalClient externalClient) {
this.externalClient = externalClient;
}
// TimeLimiter expects a CompletableFuture (async)
@Bulkhead(name = "threadPoolBulkhead", type = Bulkhead.Type.THREADPOOL, fallbackMethod = "tpbFallback")
@TimeLimiter(name = "externalServiceTL", fallbackMethod = "tlFallback")
public CompletableFuture<String> getDataAsync(String id) {
return CompletableFuture.supplyAsync(() -> externalClient.getRemoteData(id), executor);
}
public CompletableFuture<String> tpbFallback(String id, BulkheadFullException ex) {
return CompletableFuture.completedFuture("threadpool-bulkhead-fallback");
}
public CompletableFuture<String> tlFallback(String id, TimeoutException ex) {
return CompletableFuture.completedFuture("time-limiter-fallback");
}
}
组合注解 – 常见顺序
一种常见的模式是:
RateLimiter → Bulkhead → CircuitBreaker → TimeLimiter → Retry
- RateLimiter 用于防止下游服务被请求压垮。
- Bulkhead(信号量或线程池)限制您进程内部的并发使用。
- CircuitBreaker 快速阻止对出现故障的服务的调用。
- TimeLimiter 限制异步调用的延迟。
- Retry 重新执行瞬时失败(通常放在 CircuitBreaker 内部,以免放大负载)。
根据业务语义调整顺序;例如,当您希望每一次尝试都受到相同保护时,可以把 Retry 放在 CircuitBreaker 外部。
Fallback 方法要求
- Fallback 方法名必须与
fallbackMethod属性完全一致。 - 返回类型必须与被保护方法的返回类型相同。
- 参数:原方法的所有参数 加上 一个可选的最后
Throwable/Exception(或特定异常类型,如BulkheadFullException)。
这些规则确保在发生弹性事件时 Spring 能够正确地路由到对应的 fallback。