フレームワーク再試行サーキットブレーカーの構成
Spring Framework 7 は、フレームワークのレジリエンス機能の一部としてネイティブ再試行サポートを導入しました。Spring Cloud と CircuitBreaker は、Spring Framework の RetryTemplate および RetryPolicy API を使用するサーキットブレーカー実装を提供します。
Spring Framework のリトライサポートはステートレスですが、この実装では、障害を追跡し、サーキットブレーカーパターン(クローズ、オープン、ハーフオープン)を実装することで、ステートフルなサーキットブレーカー機能を追加します。この実装は、個々のリトライ回数をカウントするのではなく、1 回の実行失敗(すべてのリトライ回数の使い切り)後にサーキットブレーカーがオープンする Spring Retry の CircuitBreakerRetryPolicy をモデルにしています。
デフォルト構成
すべてのサーキットブレーカーにデフォルト設定を提供するには、Customizer、Bean を作成し、FrameworkRetryCircuitBreakerFactory を渡します。configureDefault メソッドを使用してデフォルト設定を提供できます。
@Bean
public Customizer<FrameworkRetryCircuitBreakerFactory> defaultCustomizer() {
return factory -> factory.configureDefault(id -> new FrameworkRetryConfigBuilder(id)
.retryPolicy(RetryPolicy.withMaxRetries(3))
.openTimeout(Duration.ofSeconds(20))
.resetTimeout(Duration.ofSeconds(5))
.build());
}構成オプション
FrameworkRetryConfigBuilder は次の構成オプションを提供します。
retryPolicy(RetryPolicy)- 再試行に使用する Spring FrameworkRetryPolicy。再試行の回数と条件を決定します。openTimeout(Duration)- 半開状態に移行するまでの回路の開状態を維持する時間。デフォルトは 20 秒です。resetTimeout(Duration)- 障害発生後、サーキットブレーカーの状態をリセットするまでの待機時間。このタイムアウト時間内に障害が発生しない場合、サーキットブレーカーは自動的にクローズ状態にリセットされます。デフォルトは 5 秒です。
特定のサーキットブレーカーの構成
デフォルト構成を提供するのと同様に、FrameworkRetryCircuitBreakerFactory を渡される Customizer Bean を作成して、特定のサーキットブレーカーを構成することもできます。
@Bean
public Customizer<FrameworkRetryCircuitBreakerFactory> slowCustomizer() {
return factory -> factory.configure(builder -> builder
.retryPolicy(RetryPolicy.withMaxRetries(1))
.openTimeout(Duration.ofSeconds(30))
.resetTimeout(Duration.ofSeconds(10))
.build(), "slow");
}再試行ポリシー
Spring Framework 7 には、フレームワーク再試行サーキットブレーカーで使用できるいくつかの組み込み再試行ポリシーが用意されています。
RetryPolicy.withMaxRetries(int)- 一定回数再試行するRetryPolicy.withMaxDuration(Duration)- 最大継続時間に達するまで再試行しますRetryPolicy.withBackoff(Duration, double)- 指数バックオフによる再試行RetryPolicy.forExceptions(Class<?>…)- 特定の例外型に対してのみ再試行する
and() 演算子と or() 演算子を使用してポリシーを組み合わせることもできます。
@Bean
public Customizer<FrameworkRetryCircuitBreakerFactory> customRetryPolicy() {
return factory -> factory.configureDefault(id -> new FrameworkRetryConfigBuilder(id)
.retryPolicy(RetryPolicy.withMaxRetries(3)
.and(RetryPolicy.withMaxDuration(Duration.ofSeconds(5)))
.forExceptions(IOException.class, TimeoutException.class))
.build());
}サーキットブレーカーの動作
フレームワーク再試行サーキットブレーカーの実装は、Spring Retry サーキットブレーカーパターンに従います。
閉じた状態 : リクエストは、設定された
RetryPolicyに従って許可され、再試行されます。呼び出し全体が失敗した場合(すべての再試行回数に達した場合)、回線は直ちに開きます。オープンステート : リクエストは再試行を試みることなく、フォールバックレスポンスで直ちに失敗します。
openTimeout期間後、回線はハーフオープン状態に移行します。半開き状態 : サービスが回復したかどうかをテストするために、1 つのリクエストが通過を許可されます。成功した場合、回線は閉じられます。失敗した場合、回線は再び開きます。
タイムアウトをリセット :
resetTimeout期間内に障害が発生しない場合、サーキットブレーカーは、以前は開いていたとしても、自動的に閉じた状態にリセットされます。
使用例
フレームワーク再試行サーキットブレーカーの完全な使用例を以下に示します。
@Service
public class BookService {
private final CircuitBreakerFactory circuitBreakerFactory;
private final RestTemplate restTemplate;
public BookService(CircuitBreakerFactory circuitBreakerFactory, RestTemplate restTemplate) {
this.circuitBreakerFactory = circuitBreakerFactory;
this.restTemplate = restTemplate;
}
public String getBookTitle(Long bookId) {
CircuitBreaker circuitBreaker = circuitBreakerFactory.create("bookService");
return circuitBreaker.run(
() -> restTemplate.getForObject("/books/" + bookId, String.class),
throwable -> "Fallback Book"
);
}
}設定例
@Configuration
public class CircuitBreakerConfiguration {
@Bean
public Customizer<FrameworkRetryCircuitBreakerFactory> defaultCustomizer() {
return factory -> {
// Default configuration for all circuit breakers
factory.configureDefault(id -> new FrameworkRetryConfigBuilder(id)
.retryPolicy(RetryPolicy.withMaxRetries(3)
.withBackoff(Duration.ofMillis(100), 2.0))
.openTimeout(Duration.ofSeconds(20))
.resetTimeout(Duration.ofSeconds(5))
.build());
};
}
@Bean
public Customizer<FrameworkRetryCircuitBreakerFactory> specificCustomizer() {
return factory -> {
// Specific configuration for "slow" circuit breaker
factory.configure(builder -> builder
.retryPolicy(RetryPolicy.withMaxRetries(1))
.openTimeout(Duration.ofSeconds(30))
.resetTimeout(Duration.ofSeconds(10))
.build(), "slow");
// Specific configuration for "critical" circuit breaker
factory.configure(builder -> builder
.retryPolicy(RetryPolicy.withMaxRetries(5))
.openTimeout(Duration.ofMinutes(2))
.resetTimeout(Duration.ofSeconds(15))
.build(), "critical");
};
}
}