フレームワーク再試行サーキットブレーカーの構成

Spring Framework 7 は、フレームワークのレジリエンス機能の一部としてネイティブ再試行サポートを導入しました。Spring Cloud と CircuitBreaker は、Spring Framework の RetryTemplate および RetryPolicy API を使用するサーキットブレーカー実装を提供します。

Spring Framework のリトライサポートはステートレスですが、この実装では、障害を追跡し、サーキットブレーカーパターン(クローズ、オープン、ハーフオープン)を実装することで、ステートフルなサーキットブレーカー機能を追加します。この実装は、個々のリトライ回数をカウントするのではなく、1 回の実行失敗(すべてのリトライ回数の使い切り)後にサーキットブレーカーがオープンする Spring Retry の CircuitBreakerRetryPolicy をモデルにしています。

スターター

フレームワーク再試行サーキットブレーカー実装を使用するには、次のスターターをプロジェクトに追加します。

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-circuitbreaker-framework-retry</artifactId>
</dependency>
implementation 'spring-cloud-starter-circuitbreaker-framework-retry'

デフォルト構成

すべてのサーキットブレーカーにデフォルト設定を提供するには、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 Framework RetryPolicy。再試行の回数と条件を決定します。

  • 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");
		};
	}
}

リアクティブサポート

フレームワーク Retry サーキットブレーカー実装は、リアクティブアプリケーションをサポートしていません。リアクティブサポートが必要な場合は、代わりに Resilience4J 実装を使用してください。