概要 Circuit Breaker パターンを使用してマイクロサービスの呼び出しを強化する方法を学びましょう。 そして 完全なデモ、ステップごとにコマンド、クラスごとに説明、サンプル出力、現実世界の使用ケース、および生産ヒント。 Resilience4j Spring Boot Why This Matters なぜこれが重要なのか 分散システムでは、ダウンストリームサービスの失敗がカスカデックし、システム全体の停止を引き起こす可能性があります。 パターン: Circuit Breaker 失敗した依存症を発見し、 リクエストを送るのをやめる(リソースの無駄遣いを避けるため)、 素晴らしい反応が返ってくるので、 定期的に依存性をテストし、健康なときに正常な機能を回復します。 これにより、ダウンタイムを短縮し、トレードプールを保護し、ユーザー体験を合理的に維持し、再起動嵐を防ぐことができます。 Demo Summary (What You Have) Demo Summary (What You Have) Maven Demoの2つのサービス: (port ) — simple REST provider that intentionally fails intermittently. hello-service 8081 終点ポイント GET /api/hello (port ) — calls hello-service using RestTemplate and is protected by with a fallback. client-service 8080 Resilience4j @CircuitBreaker 終点ポイント GET /api/get-message 両方( ) hello-service and client-service 次 テスト GET http://localhost:8080/api/get-message 建築図 This is a small, focused flow suitable for drawing a diagram. これは、図を描くのに適した小さな、焦点の流れです。 Files & Code: Class-By-Class Explanation Files & Code: Class-by-Class 説明 hello-service ハロウィン アプリケーション.java Standard bootstrap class. @SpringBootApplication HelloController.java @RestController public class HelloController { private static int counter = 0; @GetMapping("/api/hello") public String sayHello() { counter++; // simulate intermittent failure: fail on every 3rd request if (counter % 3 == 0) { throw new RuntimeException("Simulated failure from Hello-Service!"); } return "Hello from Hello-Service! (count=" + counter + ")"; } } このコントローラは、定期的な呼び出しに意図的に RuntimeException を投げ込んで、実際のシステム(DB 停止、悪いデータ、タイムアウト)で見られる一時的な故障をシミュレートします。 Explanation: client-service クライアントサービスアプリケーション.java スタンダード Spring Boot メインクラス 特別な設定は必要ありません。 AppConfig.java @Configuration public class AppConfig { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } } 単一の RestTemplate ベーンを提供します. 確実に RestTemplate は Spring ベーンなので、AOP/resilience プロキシが正しく動作できます。 Explanation: HelloClientService.java @Service public class HelloClientService { private final RestTemplate restTemplate; @Value("${hello.service.url}") private String helloServiceUrl; public HelloClientService(RestTemplate restTemplate) { this.restTemplate = restTemplate; } @CircuitBreaker(name = "helloService", fallbackMethod = "fallbackHello") public String getHelloMessage() { System.out.println("Calling hello service: " + helloServiceUrl); return restTemplate.getForObject(helloServiceUrl, String.class); } public String fallbackHello(Throwable t) { System.out.println("Fallback triggered: " + t); return "Hello Service is currently unavailable. Please try again later."; } } Explanation (crucial bits) @CircuitBreaker(name = "helloService", fallbackMethod = "fallbackHello") wraps the getHelloMessage() call in a circuit breaker. The name links to configuration properties. fallbackHello(Throwable t) is called when the call fails according to the breaker rules. The fallback must: o Be in the same class o Have the same return type o Accept the original method parameters (none here) and a final Throwable parameter (or Exception/Throwable compatible with thrown exceptions) Important: The method must be public, and the class must be a Spring bean (@Service), so proxy-based AOP works. ClientController.java @RestController public class ClientController { private final HelloClientService helloClientService; public ClientController(HelloClientService helloClientService) { this.helloClientService = helloClientService; } @GetMapping("/api/get-message") public String getMessage() { return helloClientService.getHelloMessage(); } } 単純なコントローラーを委任する これにより、呼び出しは、回路ブレーカーが適用されているプロキシを通過することを保証します。 Explanation: HelloClientService Configuration Used (client-service application.properties) Configuration Used(クライアントサービス application.properties) デモで使用されたキー構成 server.port=8080 spring.application.name=client-service hello.service.url=http://localhost:8081/api/hello resilience4j.circuitbreaker.instances.helloService.registerHealthIndicator=true resilience4j.circuitbreaker.instances.helloService.slidingWindowSize=5 resilience4j.circuitbreaker.instances.helloService.minimumNumberOfCalls=2 resilience4j.circuitbreaker.instances.helloService.failureRateThreshold=50 resilience4j.circuitbreaker.instances.helloService.waitDurationInOpenState=10s logging.level.io.github.resilience4j.circuitbreaker=DEBUG Meaning of important properties slidingWindowSize: ブレイカーモニターの呼び出しの数、失敗率。 minimumNumberOfCalls: 失敗率が評価される前に最低限の通話。 failureRateThreshold: 回路を開く失敗の割合(例えば、50)。 waitDurationInOpenState: 半開きに移動する前に、回路が開くまでどのくらいの時間がかかりますか。 registerHealthIndicator: actuatorを介してブレーカー状態を露出します。 Step-by-Step Run & Expected Outputs について サービス開始 ハローサービス開始 Visit: http://localhost:8081/api/hello 「Hello from Hello-Service! (or throws simulated failure)」 Returns クライアントサービス開始 Visit: http://localhost:8080/api/get-message Test Scenarios & Outputs テストシナリオ&Outputs Scenario A — Hello-Service Healthy リクエスト作成 GET http://localhost:8080/api/get-message クライアントログ Calling hello service: http://localhost:8081/api/hello 2025-11-13T11:58:23.366+05:30 DEBUG 32692 --- [client-service] [nio-8080-exec-8] i.g.r.c.i.CircuitBreakerStateMachine : CircuitBreaker 'helloService' succeeded: 2025-11-13T11:58:23.366+05:30 DEBUG 32692 --- [client-service] [nio-8080-exec-8] i.g.r.c.i.CircuitBreakerStateMachine : Event SUCCESS published: 2025-11-13T11:58:23.366634+05:30[Asia/Calcutta]: CircuitBreaker 'helloService' recorded a successful call. Elapsed time: 15 ms Response Hello from Hello-Service! (count=4) Scenario B — Hello-Service Intermittent Failures 何度も電話をかけたり、ハローサービスを投げかけたりすると、 いくつかの要請について: RuntimeException ● 成功した通話:クライアントがハローメッセージを返します。 ●ダウンストリーム通話が HTTP 500/exception を返す場合: o Resilience4j records the failure. o If failure rate exceeds threshold (e.g., 50% over sliding window), the Circuit becomes **OPEN**. o While OPEN, calls are short-circuited; **fallbackHello**() is immediately executed — no network call. \n **Client response while fallback active** Client Response while active Response Hello Service is currently unavailable. Please try again later. Sample client log sequence Calling hello service: http://localhost:8081/api/hello 2025-11-13T12:00:55.842+05:30 DEBUG 32692 --- [client-service] [nio-8080-exec-1] i.g.r.c.i.CircuitBreakerStateMachine : CircuitBreaker 'helloService' recorded an exception as failure: Scenario C — Recovery 後 オープンタイム (10s) オープンタイム Circuit は HALF_OPEN に移行します: いくつかのテスト呼び出しが許可されます。 テスト通話が成功した場合、ブレーカーが閉鎖され、通常のトラフィックが再開されます。 テストが失敗した場合、ブレーカーは OPEN に戻ります。 Real-World Use Cases リアルワールド使用ケース 支払い統合 - 外部銀行のAPIを呼び出すチェックアウトサービス:銀行のAPIが遅くなり/失敗した場合、回路ブレーカーはユーザーフレンドリーなメッセージを返し、再起動嵐を防ぐ。 Third-party rate-limited APIs - APIs with limited calls per second - when limits are reached, the circuit opens to avoid hitting quotas further; fallback returns cached data. 制限に達したときに、サーキットが開きます。 エンタープライズ内のマイクロサービスチェーン - サービスAはBを呼び、Cを呼び、Cが不安定である場合、オープンブレーカーはBとAを保護し、システム全体の減速を防ぐ。 機能の転換と優雅な劣化 - 非重要な機能サービスが失敗した場合、より単純な結果を返し、コア機能を可用に保つ(例えば、推奨なしの製品リストを返します)。 Advantages & Business Value 利点&ビジネス価値 欠陥の隔離 - 1 つの悪い依存症がカスケードするのを防ぐ。 より迅速な失敗反応 - タイムアウトを待つ代わりに迅速に失敗します。 恵み深い劣化 - 完全な中断の代わりに、倒退反応を提供します。 リソース保護:CPU、トレード、ネットワークの無駄を避ける 自動回復 - 依存症が健康であるときに自動的に正常に戻ります。 観察性 - ブレーカーの状態とメトリクスは、アクチュレータを通じて露出し、モニタリングすることができます。 Sample logs you’ll see (realistic) Calling hello service: http://localhost:8081/api/hello 2025-11-13T12:00:55.842+05:30 DEBUG 32692 --- [client-service] [nio-8080-exec-1] i.g.r.c.i.CircuitBreakerStateMachine : CircuitBreaker 'helloService' recorded an exception as failure 2025-11-13T12:00:55.847+05:30 DEBUG 32692 --- [client-service] [nio-8080-exec-1] i.g.r.c.i.CircuitBreakerStateMachine : Event ERROR published: 2025-11-13T12:00:55.847908200+05:30[Asia/Calcutta]: CircuitBreaker 'helloService' recorded an error: 'org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 : "{"timestamp":"2025-11-13T06:30:55.842+00:00","status":500,"error":"Internal Server Error","path":"/api/hello"}"'. Elapsed time: 8 ms Fallback triggered: org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 : "{"timestamp":"2025-11-13T06:30:55.842+00:00","status":500,"error":"Internal Server Error","path":"/api/hello"}"