ひとことで言うと#
電気のブレーカーと同じ発想で、呼び出し先サービスの障害を検知したら自動的に通信を遮断し、障害が連鎖(カスケード)するのを防ぐパターン。一定時間後に再接続を試みて回復を確認する。
押さえておきたい用語#
- Closed(閉)
- サーキットブレーカーの通常状態。リクエストはそのまま通過し、失敗率を記録する。
- Open(開)
- 障害を検知した状態。リクエストを即座に失敗させ、呼び出し先への通信を遮断する。フォールバック応答を返す。
- Half-Open(半開)
- 回復確認のために少量のリクエストだけ通す状態。成功すればClosedに戻り、失敗すれば再びOpenになる。
- フォールバック
- ブレーカーOpen時にユーザーに返す代替の応答。キャッシュ応答やデフォルト値など。
- カスケード障害
- 1つのサービスの障害が連鎖的に他のサービスに波及し、システム全体が停止する現象。サーキットブレーカーが防ぐ対象。
サーキットブレーカーパターンの全体像#
こんな悩みに効く#
- 1つの外部サービスの障害で、自分のシステム全体が巻き込まれて落ちてしまう
- タイムアウト待ちのリクエストが溜まり、スレッドプールが枯渇する
- 障害時にユーザーを長時間待たせてしまう
基本の使い方#
サーキットブレーカーには3つの状態がある。
- Closed(閉): 通常状態。リクエストはそのまま通過する
- Open(開): 障害検知状態。リクエストを即座に失敗させる(フォールバック応答を返す)
- Half-Open(半開): 回復確認状態。少量のリクエストだけ通し、成功すればClosedに戻る
ポイント: この3状態の遷移が、サーキットブレーカーの核心。
いつブレーカーを開くかのパラメータを決める。
- 失敗回数の閾値(例: 直近10回中5回失敗したらOpen)
- タイムアウト時間(例: 3秒以内に応答がなければ失敗とみなす)
- Open状態の維持時間(例: 30秒後にHalf-Openへ遷移)
ポイント: 閾値は厳しすぎても緩すぎてもダメ。本番の挙動を見ながらチューニングする。
ブレーカーがOpenの時に代替の応答を返す仕組みを作る。
- キャッシュされた前回の正常応答を返す
- デフォルト値や簡略化されたレスポンスを返す
- 「現在サービスが混み合っています」のようなユーザー向けメッセージを返す
ポイント: Open時に単にエラーを返すだけでは不十分。ユーザー体験を考えたフォールバックを設計する。
サーキットブレーカーの状態遷移を可視化する。
- Open/Closed/Half-Openの状態変化をメトリクスとして記録する
- Open状態への遷移をアラートで通知する
- ダッシュボードで全サービスのブレーカー状態を一覧できるようにする
ポイント: ブレーカーが開いたことに気づけなければ、根本原因の対処が遅れる。
具体例#
状況: ECサイトの注文処理が外部決済APIを呼び出している。決済APIが不安定になると注文処理全体がタイムアウトで詰まる。
Closed状態: 決済APIへのリクエストは通常通り送信。レスポンスタイムと成功率を記録。
障害発生: 決済APIが応答しなくなる。直近20リクエスト中15回がタイムアウト → 閾値(75%)超え → Open状態に遷移。
Open状態: 決済APIへのリクエストを即座にブロック。「決済処理を一時的に受け付けられません。しばらくしてから再度お試しください」とユーザーに返す。スレッドプールの枯渇を防止。
30秒後 → Half-Open: 1リクエストだけ決済APIに送信。成功 → Closed状態に復帰。失敗 → 再びOpenで30秒待つ。
結果: 決済APIの障害中も商品閲覧・カート操作は正常に動作し続けた。スレッドプール枯渇によるシステム全体の停止を回避した。
状況: 注文→在庫→出荷→通知の4サービスが連鎖呼び出し。通知サービスのDB障害で通知が遅延 → 出荷サービスのスレッドが枯渇 → 在庫サービスも停止 → 注文不能に。年に3回このカスケード障害が発生。
サーキットブレーカー導入:
- 各サービス間の呼び出しにResilience4jのCircuit Breakerを適用
- 失敗率50%超でOpen、30秒後にHalf-Open
- 通知サービス: フォールバックは非同期キューに投入(後で再送)
- 在庫サービス: フォールバックはキャッシュされた在庫数を返す(10秒前のデータ)
結果: 通知サービスが障害を起こしても、注文・在庫・出荷は正常動作を維持。カスケード障害の発生が年3回→ゼロになり、年間のダウンタイムが4.5時間→15分に短縮した。
状況: 旅行予約サイトが外部天気APIを呼び出して旅行先の天気情報を表示。天気APIが月に2〜3回スローダウン(レスポンス8秒)し、その間ページ全体の表示が遅延。
設計:
- タイムアウト: 2秒
- 閾値: 直近10リクエスト中4回タイムアウトでOpen
- Open維持時間: 60秒
- フォールバック: 「天気情報を取得中です」のプレースホルダーを表示し、クライアントサイドで非同期リロード
結果: 天気APIのスローダウン時、サーキットブレーカーが2秒以内にOpenに遷移。ページ全体のレスポンスタイムが8秒→1.2秒に改善(天気なしでの表示)。ユーザーのページ離脱率が天気API障害時に38%→12%に低下した。
やりがちな失敗パターン#
- 閾値を固定値のまま放置する — トラフィックが増えると正常時でも閾値に達してしまう。失敗率(パーセンテージ)ベースの閾値を使うこと
- フォールバックを設計しない — Open時にただエラーを返すだけだと、ブレーカーの意味が半減する。ユーザー体験を維持するフォールバックを必ず用意する
- Half-Open時のリクエスト数が多すぎる — 回復確認で大量リクエストを送ると、回復しかけたサービスを再び潰す。最小限のリクエストで回復を確認する
- ブレーカーの状態変化をモニタリングしない — Openに遷移したことに誰も気づかず、フォールバック状態が長時間続く。状態遷移をアラートで即時通知する仕組みが必須
まとめ#
サーキットブレーカーは分散システムにおける 「安全装置」。障害を検知して自動的に通信を遮断し、システム全体の連鎖的な障害を防ぐ。Closed → Open → Half-Open の3状態遷移を正しく設計し、フォールバックとモニタリングを組み合わせることで、レジリエントなシステムを実現しよう。