重试机制 #
一、重试概述 #
1.1 为什么需要重试 #
text
无重试:
客户端 ──► 服务 (临时故障)
│
└── 请求失败 ──► 用户看到错误
有重试:
客户端 ──► 服务 (临时故障)
│
├── 第1次失败
├── 第2次失败
└── 第3次成功 ──► 用户正常使用
1.2 重试场景 #
| 场景 | 是否适合重试 |
|---|---|
| 网络超时 | ✅ 适合 |
| 服务临时不可用 | ✅ 适合 |
| 业务异常 | ❌ 不适合 |
| 参数校验失败 | ❌ 不适合 |
二、基本使用 #
2.1 添加依赖 #
xml
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-retry</artifactId>
</dependency>
2.2 配置重试 #
yaml
resilience4j:
retry:
configs:
default:
maxAttempts: 3
waitDuration: 500ms
enableExponentialBackoff: true
exponentialBackoffMultiplier: 2
instances:
userService:
baseConfig: default
orderService:
baseConfig: default
maxAttempts: 5
2.3 使用注解 #
java
@Service
public class UserService {
@Retry(name = "userService", fallbackMethod = "getUserFallback")
public User getUser(Long id) {
return userClient.getUserById(id);
}
private User getUserFallback(Long id, Throwable t) {
log.error("Retry failed for getUser, id: {}", id, t);
return createDefaultUser(id);
}
}
三、配置详解 #
3.1 完整配置 #
yaml
resilience4j:
retry:
configs:
default:
maxAttempts: 3
waitDuration: 500ms
enableExponentialBackoff: true
exponentialBackoffMultiplier: 2
enableRandomizedWait: false
randomizedWaitFactor: 0.5
retryExceptions:
- java.io.IOException
- java.net.SocketTimeoutException
ignoreExceptions:
- com.example.BusinessException
instances:
userService:
baseConfig: default
3.2 配置项说明 #
| 配置项 | 默认值 | 说明 |
|---|---|---|
| maxAttempts | 3 | 最大重试次数 |
| waitDuration | 500ms | 重试等待时间 |
| enableExponentialBackoff | false | 是否启用指数退避 |
| exponentialBackoffMultiplier | 2 | 指数退避乘数 |
| enableRandomizedWait | false | 是否启用随机等待 |
| randomizedWaitFactor | 0.5 | 随机等待因子 |
| retryExceptions | - | 触发重试的异常 |
| ignoreExceptions | - | 忽略的异常 |
四、退避算法 #
4.1 固定间隔 #
yaml
resilience4j:
retry:
configs:
default:
maxAttempts: 3
waitDuration: 1s
text
第1次 ──► 等待1s ──► 第2次 ──► 等待1s ──► 第3次
4.2 指数退避 #
yaml
resilience4j:
retry:
configs:
default:
maxAttempts: 3
waitDuration: 500ms
enableExponentialBackoff: true
exponentialBackoffMultiplier: 2
text
第1次 ──► 等待500ms ──► 第2次 ──► 等待1000ms ──► 第3次
4.3 随机退避 #
yaml
resilience4j:
retry:
configs:
default:
maxAttempts: 3
waitDuration: 500ms
enableRandomizedWait: true
randomizedWaitFactor: 0.5
text
第1次 ──► 等待250ms~750ms ──► 第2次 ──► 等待250ms~750ms ──► 第3次
五、异常处理 #
5.1 指定重试异常 #
yaml
resilience4j:
retry:
configs:
default:
maxAttempts: 3
retryExceptions:
- java.io.IOException
- java.net.SocketTimeoutException
- org.springframework.web.client.HttpServerErrorException
5.2 忽略异常 #
yaml
resilience4j:
retry:
configs:
default:
maxAttempts: 3
ignoreExceptions:
- com.example.BusinessException
- com.example.ValidationException
5.3 自定义异常判断 #
java
@Configuration
public class RetryConfig {
@Bean
public Retry userServiceRetry() {
RetryConfig config = RetryConfig.custom()
.maxAttempts(3)
.waitDuration(Duration.ofMillis(500))
.retryOnException(throwable -> {
if (throwable instanceof BusinessException) {
return false;
}
return true;
})
.build();
return Retry.of("userService", config);
}
}
六、编程式使用 #
6.1 创建重试器 #
java
@Configuration
public class RetryConfig {
@Bean
public Retry userServiceRetry() {
RetryConfig config = RetryConfig.custom()
.maxAttempts(3)
.waitDuration(Duration.ofMillis(500))
.enableExponentialBackoff()
.exponentialBackoffMultiplier(2)
.build();
return Retry.of("userService", config);
}
}
6.2 使用重试器 #
java
@Service
public class UserService {
@Autowired
private Retry retry;
public User getUser(Long id) {
Supplier<User> supplier = Retry.decorateSupplier(
retry,
() -> userClient.getUserById(id)
);
return Try.ofSupplier(supplier)
.recover(throwable -> createDefaultUser(id))
.get();
}
}
6.3 异步重试 #
java
@Service
public class UserService {
@Autowired
private Retry retry;
public CompletableFuture<User> getUserAsync(Long id) {
Supplier<CompletableFuture<User>> supplier = Retry.decorateCompletionStage(
retry,
Executors.newFixedThreadPool(10),
() -> CompletableFuture.supplyAsync(() -> userClient.getUserById(id))
);
return supplier.get();
}
}
七、组合使用 #
7.1 重试+熔断 #
java
@Service
public class UserService {
@Retry(name = "userService")
@CircuitBreaker(name = "userService", fallbackMethod = "fallback")
public User getUser(Long id) {
return userClient.getUserById(id);
}
private User fallback(Long id, Throwable t) {
return createDefaultUser(id);
}
}
7.2 重试+限流 #
java
@Service
public class UserService {
@RateLimiter(name = "userService")
@Retry(name = "userService", fallbackMethod = "fallback")
public User getUser(Long id) {
return userClient.getUserById(id);
}
private User fallback(Long id, Throwable t) {
return createDefaultUser(id);
}
}
八、事件监听 #
8.1 配置事件监听 #
java
@Configuration
public class RetryEventConfig {
@Bean
public RetryEventListener retryEventListener(RetryRegistry registry) {
registry.getAllRetries().forEach(retry -> {
retry.getEventPublisher()
.onRetry(event -> log.info("Retry: {}", event))
.onSuccess(event -> log.info("Retry success: {}", event))
.onError(event -> log.error("Retry error: {}", event));
});
return new RetryEventListener();
}
}
8.2 事件类型 #
| 事件类型 | 说明 |
|---|---|
| RetryOnRetryEvent | 重试事件 |
| RetryOnSuccessEvent | 重试成功 |
| RetryOnErrorEvent | 重试失败 |
九、最佳实践 #
9.1 生产环境配置 #
yaml
resilience4j:
retry:
configs:
default:
maxAttempts: 3
waitDuration: 500ms
enableExponentialBackoff: true
exponentialBackoffMultiplier: 2
retryExceptions:
- java.io.IOException
- java.net.SocketTimeoutException
- org.springframework.web.client.HttpServerErrorException
ignoreExceptions:
- com.example.BusinessException
instances:
userService:
baseConfig: default
orderService:
baseConfig: default
maxAttempts: 5
9.2 注意事项 #
| 注意点 | 说明 |
|---|---|
| 幂等性 | 重试操作必须是幂等的 |
| 重试次数 | 避免过多重试 |
| 退避策略 | 使用指数退避避免雪崩 |
| 异常分类 | 区分可重试和不可重试异常 |
十、总结 #
10.1 核心要点 #
| 要点 | 说明 |
|---|---|
| 重试次数 | maxAttempts控制 |
| 退避策略 | 固定/指数/随机 |
| 异常处理 | retryExceptions/ignoreExceptions |
| 幂等性 | 重试操作必须幂等 |
10.2 下一步 #
现在你已经掌握了重试机制的使用,接下来让我们学习 配置中心,了解如何管理微服务配置!
最后更新:2026-03-28