Spring Cloud Circuit Breaker

Spring Cloud サーキットブレーカーは、さまざまなサーキットブレーカー実装にわたる抽象化を提供します。アプリケーションで使用する一貫した API が提供されるため、開発者はアプリケーションのニーズに最適なサーキットブレーカーの実装を選択できます。

サポートされている実装

Spring Cloud は、次のサーキットブレーカーの実装をサポートしています。

コアコンセプト

コード内にサーキットブレーカーを作成するには、CircuitBreakerFactory API を使用できます。Spring Cloud Circuit Breaker スターターをクラスパスに含めると、この API を実装する Bean が自動的に作成されます。次の例は、この API の使用方法の簡単な例を示しています。

@Service
public static class DemoControllerService {
	private RestTemplate rest;
	private CircuitBreakerFactory cbFactory;

	public DemoControllerService(RestTemplate rest, CircuitBreakerFactory cbFactory) {
		this.rest = rest;
		this.cbFactory = cbFactory;
	}

	public String slow() {
		return cbFactory.create("slow").run(() -> rest.getForObject("/slow", String.class), throwable -> "fallback");
	}

}

CircuitBreakerFactory.create API は、CircuitBreaker というクラスのインスタンスを作成します。run メソッドは Supplier と Function を受け取ります。Supplier は、サーキットブレーカーにラップするコードです。Function は、サーキットブレーカーが作動した場合に実行されるフォールバックです。この関数には、フォールバックをトリガーした Throwable が渡されます。フォールバックを提供したくない場合は、オプションでフォールバックを除外できます。

リアクティブコードのサーキットブレーカー

プロジェクト Reactor がクラスパス上にある場合は、リアクティブコードに ReactiveCircuitBreakerFactory を使用することもできます。次の例は、その方法を示しています。

@Service
public static class DemoControllerService {
	private ReactiveCircuitBreakerFactory cbFactory;
	private WebClient webClient;


	public DemoControllerService(WebClient webClient, ReactiveCircuitBreakerFactory cbFactory) {
		this.webClient = webClient;
		this.cbFactory = cbFactory;
	}

	public Mono<String> slow() {
		return webClient.get().uri("/slow").retrieve().bodyToMono(String.class).transform(
		it -> cbFactory.create("slow").run(it, throwable -> return Mono.just("fallback")));
	}
}

ReactiveCircuitBreakerFactory.create API は、ReactiveCircuitBreaker というクラスのインスタンスを作成します。run メソッドは、Mono または Flux を受け取り、それをサーキットブレーカーでラップします。オプションでフォールバック Function をプロファイリングできます。フォールバック Function は、サーキットブレーカーが作動し、障害の原因となった Throwable が渡された場合に呼び出されます。

構成

型 Customizer の Bean を作成することで、サーキットブレーカーを構成できます。Customizer インターフェースには、Object を使用してカスタマイズする単一のメソッド ( customize と呼ばれる) があります。

特定の実装をカスタマイズする方法の詳細については、次のドキュメントを参照してください。

Resilience4JCircuitBreaker などの一部の CircuitBreaker 実装は、CircuitBreaker#run が呼び出されるたびに customize メソッドを呼び出します。非効率的になる可能性があります。その場合は、CircuitBreaker#once メソッドを使用できます。これは、たとえば、Resilience4j のイベントを使用する (英語) 場合など、customize を何度も呼び出すことが意味がない場合に役立ちます。

次の例は、各 io.github.resilience4j.circuitbreaker.CircuitBreaker がイベントを消費する方法を示しています。

Customizer.once(circuitBreaker -> {
  circuitBreaker.getEventPublisher()
    .onStateTransition(event -> log.info("{}: {}", event.getCircuitBreakerName(), event.getStateTransition()));
}, CircuitBreaker::getName)

Spring HTTP サービスクライアントサポート

Spring Cloud は、次のコンフィギュレータを通じて Spring HTTP サービスクライアントの統合をサポートします。

  • CircuitBreakerRestClientHttpServiceGroupConfigurer

  • CircuitBreakerWebClientHttpServiceGroupConfigurer

これらのコンフィギュレータは、Spring HTTP サービスクライアントグループの CircuitBreaker サポートを有効にします。

フォールバッククラスが @HttpServiceFallbackAnnotation を使用して構成されている場合、CircuitBreaker アダプターデコレータが追加されます: - CircuitBreakerAdapterDecorator は RestClient とともに使用されます - ReactiveCircuitBreakerAdapterDecorator は WebClient とともに使用されます

適切なプロパティを設定することで、HTTP サービスクライアントの CircuitBreaker 統合を無効にすることができます。

  • ブロッキング(RestClient)クライアントの場合: spring.cloud.circuitbreaker.http-services.enabled=false

  • リアクティブ(WebClient)クライアントの場合: spring.cloud.circuitbreaker.reactive-http-services.enabled=false

これにより、CircuitBreaker デコレータがインターフェースベースの HTTP クライアントグループに適用されなくなります。

アノテーションによるフォールバックの宣言

フォールバックは、設定クラスの @HttpServiceFallback アノテーションを使用して設定されます。このアノテーションでは、以下の宣言が可能です。

  • フォールバック実装クラス (value 経由)

  • フォールバックがサポートするサービスインターフェース (forService 経由、オプション)

  • フォールバックが適用されるグループ (forGroup 経由、オプション)

Java の @Repeatable アノテーション機構を使用すると、同じクラスに複数の @HttpServiceFallback アノテーションを宣言できます。グループが指定されていない場合、フォールバックは、指定されたサービスインターフェースに対してグループごとに明示的なフォールバックが指定されていないすべてのグループに適用されます。

フォールバッククラスは次の優先順位を使用して解決されます。

  1. forService と forGroup の両方が一致するフォールバッククラス

  2. forService に一致し、forGroup がないフォールバッククラス (サービスのグローバルフォールバック)

  3. forService または forGroup のないフォールバッククラス (グループ内またはグローバルのすべてのサービスのデフォルト)

サンプル

@HttpServiceFallback(value = DefaultFallbacks.class)
@HttpServiceFallback(value = GroupAndServiceSpecificFallbacks.class, service = {BillingService.class, ShippingService.class}, group = "billing")
public class MyFallbackConfig {
    ...
}

この構成の結果は次のようになります。

  • DefaultFallbacks は、明示的に処理されないすべてのサービスのグローバルフォールバックとして使用されます。

  • GroupAndServiceSpecificFallbacks は "billing" グループ内の BillingService と ShippingService にのみ使用されます

  • フォールバッククラスとそのメソッドは public である必要があります

  • フォールバックメソッドには @HttpExchange アノテーションを付けてはいけません

CircuitBreaker アダプターの仕組み

アダプターは @HttpExchange メソッド呼び出しを CircuitBreaker ロジックでラップします。フォールバックがトリガーされると、ユーザー定義のフォールバッククラスを使用してプロキシが作成されます。適切なフォールバックメソッドは、以下の条件に基づいて選択されます。

  • 同じ名前とパラメーター型を持つメソッド、または

  • 同じ名前とパラメーター型を持ち、その前に Throwable 引数が付くメソッド (失敗の原因にアクセスする)

次のインターフェースがあるとします。

@HttpExchange("/test")
public interface TestService {

    @GetExchange("/{id}")
    Person test(@PathVariable UUID id);

    @GetExchange
    String test();
}

一致するフォールバッククラスは次のようになります。

public class TestServiceFallback {

    public Person test(UUID id);

    public String test(Throwable cause);
}