解鎖 Spring Boot:四種重試機制方案全攻略
前言
在分布式系統和微服務架構盛行的當下,服務調用失敗的情況時有發生,網絡波動、服務過載或臨時故障等因素都可能導致調用失敗。為提升系統可用性,重試機制成為處理臨時性故障的有效手段。
本文將探討Spring Boot中4種重試機制的實現方案,助力開發者根據項目需求精準選型。
Guava Retrying
基本原理
Guava Retrying 是 Google Guava 庫提供的重試機制,通過構建器模式實現靈活配置,可自定義重試條件、停止策略、等待策略等,為開發者提供了強大的控制能力。
使用方法
主要采用編程方式,通過RetryerBuilder構建Retryer實例,設置重試條件、等待策略、停止策略等。還可添加重試監聽器,在重試過程中記錄日志或執行其他操作。也可將Retryer定義為可復用的bean,提高代碼復用性。
詳細案例見《如何優雅實現接口服務的重試機制》,推薦這款
Spring Retry
基本原理
Spring Retry作為Spring官方出品的重試框架,借助AOP實現方法調用重試。核心組件涵蓋定義重試操作接口的RetryOperations,其默認實現RetryTemplate,以及定義重試條件的RetryPolicy、控制重試間隔的BackOffPolicy和最終失敗恢復策略的RecoveryCallback。當方法調用失敗,它會依據配置策略自動重試,直至成功或達到最大重試次數。
使用方法
- 注解方式:使用@Retryable注解標記需重試的方法,指定觸發重試的異常類型、最大重試次數和退避策略。@Recover注解用于定義重試失敗后的恢復方法,代碼簡潔直觀,適用于簡單場景。
- 編程方式:通過注入RetryTemplate實例,在方法內調用execute方法,傳入重試業務邏輯和失敗恢復邏輯。還可自定義RetryTemplate的重試策略和退避策略,滿足復雜業務需求。
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
@Override
@Retryable(maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier = 2))
public void addOrder() {
System.out.println("重試...");
int i = 3 / 0;
// addOrder
}
@Recover
public void recover(RuntimeException e) {
log.error("達到最大重試次數", e);
}
}
public void normalSpringRetry() {
// 表示哪些異常需要重試,key表示異常的字節碼,value為true表示需要重試
Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>();
exceptionMap.put(RetryException.class, true);
// 構建重試模板實例
RetryTemplate retryTemplate = new RetryTemplate();
// 設置重試回退操作策略,主要設置重試間隔時間
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
long fixedPeriodTime = 1000L;
backOffPolicy.setBackOffPeriod(fixedPeriodTime);
// 設置重試策略,主要設置重試次數
int maxRetryTimes = 3;
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(maxRetryTimes, exceptionMap);
retryTemplate.setRetryPolicy(retryPolicy);
retryTemplate.setBackOffPolicy(backOffPolicy);
Boolean execute = retryTemplate.execute(
//RetryCallback
retryContext -> {
String hello = helloService.hello();
log.info("調用的結果:{}", hello);
returntrue;
},
// RecoverCallBack
retryContext -> {
//RecoveryCallback
log.info("已達到最大重試次數");
returnfalse;
}
);
}
Resilience4j Retry
基本原理
Resilience4j Retry受Netflix Hystrix啟發,是輕量級容錯庫。它采用函數式編程風格和裝飾器模式實現重試功能,具備基于函數式接口、無外部依賴、可與其他容錯機制無縫集成以及提供豐富監控指標等特性。
使用方法
- 注解方式:使用@Retry注解標記方法,指定重試實例名稱和降級方法,簡潔方便,適用于簡單業務場景。
- 編程方式:從RetryRegistry獲取已配置的重試實例,使用Retry.decorateCheckedSupplier方法裝飾業務方法,在try-catch塊中執行重試邏輯并處理失敗情況,靈活性更高。
resilience4j.retry:
instances:
backendService:
maxAttempts: 3
waitDuration: 1s
enableExponentialBackoff: true
exponentialBackoffMultiplier: 2
retryExceptions:
- java.io.IOException
- java.util.concurrent.TimeoutException
@Service
public class OrderServiceImpl implements OrderService {
@Override
@Retry(name = "addOrder", fallbackMethod = "recover")
public void addOrder() {
System.out.println("重試...");
int i = 3 / 0;
// addOrder
}
public void recover((String param, Exception ex) {
log.error("達到最大重試次數", e);
}
}
@Service
public class HelloService {
private final RetryRegistry retryRegistry;
public String executeWithRetry(String param) {
// 獲取已配置的重試實例
Retry retry = retryRegistry.retry("helloService");
// 創建一個可重試的函數
CheckedFunction0<String> retryableFunction = Retry.decorateCheckedSupplier(
retry, () -> callHelloService(param));
try {
// 執行重試函數
return retryableFunction.apply();
} catch (Throwable throwable) {
return"降級響應: " + param;
}
}
private String callHelloService(String param) throws IOException {
if (Math.random() > 0.7) {
throw new IOException("服務連接失敗");
}
return"后端服務響應: " + param;
}
}
Failsafe
基本原理
Failsafe專注于高性能和低延遲場景,支持同步和異步重試,具有靈活的重試策略和極少的依賴。其設計目標是提供簡潔高效的重試機制,讓開發者能輕松應對各種重試需求。
使用方法
主要通過編程方式,利用流式API進行配置。可配置重試策略,包括處理的異常類型、最大重試次數、延遲時間、最大持續時間、退避策略等,還可添加重試和失敗監聽器。同時支持異步重試和帶降級的重試,滿足不同業務場景需求。也可將重試策略和降級策略定義為可復用的bean,提升代碼復用性。
@Slf4j
@Service
public class FailsafeService {
public String executeWithRetry(String param) {
return Failsafe.with(
// 配置重試策略
RetryPolicy.<String>builder()
.handle(IOException.class, TimeoutException.class)
.withMaxRetries(3)
.withDelay(Duration.ofSeconds(1))
.withMaxDuration(Duration.ofSeconds(10))
.withBackoff(Duration.ofMillis(100), Duration.ofSeconds(2))
.onRetry(event -> log.info("第{}次重試,上次異常: {}",
event.getAttemptCount(),
event.getLastException().getMessage()))
.onFailure(event -> log.error("重試失敗,嘗試次數: {}, 總耗時: {}ms",
event.getAttemptCount(),
event.getElapsedTime().toMillis()))
.build()
)
.get(() -> {
log.info("執行操作,參數: {}", param);
// 模擬操作
if (Math.random() > 0.7) {
throw new IOException("操作暫時失敗");
}
return"操作成功: " + param;
});
}
// 異步重試示例
public CompletableFuture<String> executeWithRetryAsync(String param) {
return Failsafe.with(
RetryPolicy.<String>builder()
.handle(IOException.class)
.withMaxRetries(3)
.withBackoff(Duration.ofMillis(100), Duration.ofSeconds(1))
.build()
)
.getAsync(() -> {
log.info("異步執行操作,參數: {}", param);
// 模擬異步操作
if (Math.random() > 0.7) {
throw new IOException("異步操作暫時失敗");
}
return"異步操作成功: " + param;
});
}
// 帶降級的重試示例
public String executeWithFallback(String param) {
return Failsafe.with(
RetryPolicy.<String>builder()
.handle(IOException.class)
.withMaxRetries(3)
.build(),
// 降級策略
Fallback.of(e -> "降級響應: " + param)
)
.get(() -> {
// 業務邏輯
if (Math.random() > 0.7) {
throw new IOException("操作失敗");
}
return"操作成功: " + param;
});
}
}
總結
在實際開發中,開發者可根據業務場景的特點,靈活運用這些重試機制,提升系統的容錯能力和用戶體驗。