LASSIC Media らしくメディア
サーキットブレーカー等レジリエンス設計を外注
LASSIC IT事業部|元請(プライムベンダー)としてシステム保守・運用を受託
この記事のポイント
- サーキットブレーカー・リトライ・バルクヘッドなど、サービス間呼び出しを守るレジリエンス設計パターンの役割を整理します。
- 一部の遅延・障害がシステム全体に波及するカスケード障害の仕組みと、代表的な対策パターンの関係を解説します。
- 導入時の論点と、外注する場合の委託範囲・発注準備のポイントをまとめます。
目次
カスケード障害を防ぐレジリエンス設計とは
サーキットブレーカー・リトライ・レジリエンス設計とは、分散システムを構成するサービス同士の呼び出しにおいて、一部の遅延・障害が呼び出し元に連鎖し、システム全体が停止する事態を防ぐための設計手法を指します*1。Microsoft Azure Architecture Centerは、リモートサービスへの呼び出しが一時的な障害(過負荷・接続の一時的な断・タイムアウトなど)によって失敗しうることを前提に、こうした障害へ備える設計パターン群を提示しています*1。
分散システムでは、複数のサービス(マイクロサービスやAPI、データベースなど)が相互にネットワーク越しで呼び出し合う構成が一般的です。あるサービスが応答遅延や一時的な過負荷を起こすと、そのサービスを呼び出している上位のサービスも応答を待ち続け、さらにその上位も待たされる、という形で影響が連鎖することがあります。
Azure Architecture Centerは、あるサービスが処理待ちで反応しない状態が続くと、それを呼び出す側の処理がタイムアウトまで応答を保留し、メモリ・スレッド・データベース接続といった重要なシステムリソースを保持し続けることでリソースが枯渇し、システムの無関係な他の部分にまで障害が及ぶ可能性があると説明しています*1。これがカスケード障害(連鎖的障害)と呼ばれる現象です。
この問題への対処として、Azure Architecture Centerはリトライパターン・サーキットブレーカーパターンを、Netflixのエンジニアリング組織を起点に広まったHystrixの設計思想を整理したMartin Fowlerはサーキットブレーカーパターンを、それぞれ紹介しています*1*2。あわせてバルクヘッド(隔壁)パターンによるリソース分離も、カスケード障害を防ぐ設計として位置づけられています*3。次章以降で、それぞれのパターンの仕組みを順に見ていきます。
サーキットブレーカー — 閉・開・半開の状態遷移で失敗を遮断
サーキットブレーカーパターンは、失敗する可能性が高い処理を繰り返し実行してしまうことを防ぐパターンです。Martin Fowlerは、これを電気回路のブレーカーになぞらえたステートマシン(状態機械)として説明しています*2。
状態は3つに分かれます。Azure Architecture Centerの整理によると、Closed(閉)状態では要求が通常どおり処理先へルーティングされ、プロキシは直近の失敗回数を記録します*1。失敗回数が一定期間内に指定の閾値を超えると、プロキシはOpen(開)状態へ移行し、タイムアウトタイマーを開始します*1。
Open状態では、アプリケーションからの要求は実際の呼び出しを行わずに即座に失敗として扱われ、例外が返されます*1。この間、システム側では障害の原因を解消するための時間が確保されます*1。タイマーが満了すると、状態はHalf-Open(半開)へ移行します*1。
Half-Open状態では、限られた数の要求だけが実際の処理先への呼び出しを許可されます*1。これらの要求が成功すれば、サーキットブレーカーは障害が解消したと判断してClosed状態に戻り、失敗カウンタをリセットします*1。逆にいずれかの要求が失敗すれば、障害がまだ続いていると判断してOpen状態に戻り、タイムアウトタイマーを再始動します*1。
Half-Open状態を挟む理由について、Azure Architecture Centerは、回復途上のサービスに要求が一気に集中することを防ぐためだと説明しています*1。サービスが復旧する過程では、完全復旧までの間は限られた量の要求しか処理できないことがあり、そこに要求が殺到するとタイムアウトや再失敗を招きかねないためです*1。
Azure Architecture Centerは、サーキットブレーカーパターンとリトライパターンの目的の違いも明確にしています。リトライパターンは「最終的に成功する」という前提で操作を再試行するのに対し、サーキットブレーカーパターンは「失敗する可能性が高い操作の実行そのものを防ぐ」ためのパターンだとされています*1。両者は、サーキットブレーカー経由でリトライパターンを呼び出す形で組み合わせることができるとも述べられています*1。
リトライ・タイムアウト・バルクヘッド・フォールバック
サーキットブレーカー以外にも、サービス間呼び出しを守る設計パターンがいくつか存在します。ここでは代表的な4つを整理します。
リトライ(再試行)
Azure Architecture Centerは、リモートサービスへの一時的な障害(ネットワークの瞬断・サービスの一時的な高負荷・タイムアウトなど)は自己回復することが多く、適切な遅延を挟んで再試行すれば成功する可能性があるとしています*4。障害が検知された場合の対応として、即座に失敗を報告して処理を中止する「取消」、まれな障害であればすぐに再試行する「即時再試行」、接続やサービスの混雑が原因であれば遅延を挟んで再試行する「遅延後再試行」の3つの戦略が挙げられています*4。
再試行の間隔については、要求を複数回重ねるにつれて遅延を段階的または指数関数的に増やす方法があるとされ、これは失敗の種類や短時間で解消される見込みに応じて選ぶべきだと説明されています*4。あわせて、複数のアプリケーションインスタンスからの要求をできるだけ均等に分散させ、混雑しているサービスへの負荷集中を避けることも狙いの一つとされています*4。
Azure Architecture Centerは、遅延が極めて短くリトライ回数が多い積極的な再試行方針は、容量の限界近くで稼働している混雑サービスをさらに悪化させかねないと注意を促しています*4。一定回数の再試行を経てもなお失敗する場合は、それ以上の要求を止めて即座に失敗を報告し、サーキットブレーカーパターンで扱うべきだとも述べています*4。また、対象の処理がべき等(同じ処理を何度実行しても結果が変わらない性質)かどうかを確認する必要があるとしています。べき等でない処理を再試行すると、意図しない重複実行が起こりうるためです*4。
タイムアウト(応答待ちの上限設定)
Azure Architecture Centerは、サービスが混雑している場合、あるサービスを呼び出す処理にタイムアウトを設定し、規定時間内に応答がなければ失敗として扱う構成を例に挙げています*1。ただしこの方法は、タイムアウトの満了まで同一処理への並行要求をブロックしうるため、その間にメモリ・スレッド・データベース接続といったリソースを保持し続け、他の無関係な処理にまで影響が及ぶ場合があると指摘しています*1。処理が成功する見込みが高い場合にのみ呼び出しを行う設計と組み合わせ、タイムアウトの長さは「多くの場合で処理が成功できる程度に長く、かつ短く」調整する必要があるとされています*1。
バルクヘッド(リソース隔離)
バルクヘッドパターンは、船体の隔壁(バルクヘッド)が浸水を一区画に閉じ込め、船全体の沈没を防ぐ仕組みになぞらえた設計です*3。Azure Architecture Centerは、あるサービスの呼び出しに使うリソース(例えば接続プール)を、別のサービスの呼び出しに使うリソースと分離しておけば、一方のサービスで障害が起きても、その影響を該当するリソースプール内に閉じ込められると説明しています*3。
具体例として、複数のサービスを呼び出すコンシューマーが、サービスごとに専用の接続プールを割り当てておく構成が挙げられています。あるサービスが失敗し始めても、影響はそのサービス用の接続プールに限定され、コンシューマーは他のサービスの利用を継続できるとされています*3。Azure Architecture Centerは、より高度な障害対応のためにバルクヘッドをリトライ・サーキットブレーカー・スロットリングの各パターンと組み合わせることも推奨しています*3。
フォールバック(代替応答)
Azure Architecture Centerのサーキットブレーカーパターンの解説では、Open状態において例外を返す代わりに、アプリケーションにとって意味のある既定値を返す構成も可能だとされています*1。呼び出し元が例外を処理できることを前提に、キャッシュ済みのデータを返す、機能を一時的に縮退させる、代替の処理で同等のタスクを試みるといった対応が挙げられています*1。フォールバックは、遮断した呼び出しの代わりに何を返すかという「遮断後の振る舞い」を担う要素だといえます。
パラメータ調整と監視 — 導入時に詰めるべき論点
これらのパターンは仕組みを理解するだけでなく、自社のサービス特性に合わせてパラメータを調整し、継続的に監視する体制と組み合わせて初めて機能します。導入時に詰めるべき論点を整理します。
失敗閾値・タイムアウト時間の調整
Azure Architecture Centerは、サーキットブレーカーの回復時間は保護対象の処理が実際に回復する傾向に合わせて設定すべきだとしています。Open状態を長く保ちすぎると、原因がすでに解消していても例外を返し続けることになり、逆にOpen状態からHalf-Open状態への切り替えが早すぎると、応答時間が不安定になる場合があるとされています*1。障害の種類によって扱いを変える工夫にも触れられており、例えばサービスのクラッシュのように回復に数分を要する障害と、過負荷による一時的なタイムアウトとでは、サーキットブレーカーをOpen状態に切り替えるまでに許容する例外の数を変える余地があるとされています*1。
これらの閾値は一次情報にも具体的な推奨値が示されておらず、対象サービスの応答特性・呼び出し頻度・許容できる遅延を踏まえて個別に検証する必要があります。数値を検証せずに固定値を流用すると、閾値が厳しすぎて正常時にも遮断が発生したり、逆に緩すぎてカスケード障害を防げなかったりする事態につながります。
監視・可観測性との連携
Azure Architecture Centerは、サーキットブレーカーが状態変化のたびにイベントを発行できるようにしておけば、保護対象のコンポーネントの健全性を監視したり、Open状態への切り替わりを管理者に通知したりする材料になると述べています*1。バルクヘッドパターンについても、各パーティション(隔離単位)のパフォーマンスとサービスレベル合意(SLA)を監視することが論点として挙げられています*3。障害の発生と復旧の履歴を可視化できなければ、閾値の妥当性を継続的に検証すること自体が難しくなります。
多重防御としての組み合わせ
いずれのパターンも単独で万能ではありません。タイムアウトで応答待ちを打ち切り、リトライで一時的な障害から回復を試み、リトライでも解消しない障害はサーキットブレーカーで遮断し、呼び出し先ごとにバルクヘッドでリソースを隔離する、という形で多重に組み合わせることで、カスケード障害への耐性を段階的に高める設計になります*1*3。Azure Architecture Centerも、より高度な障害対応のためにバルクヘッドをリトライ・サーキットブレーカーと組み合わせる方針を挙げています*3。
過剰適用の回避
Azure Architecture Centerは、サーキットブレーカーパターンについて、インメモリのデータ構造のようなアプリケーション内のローカルなプライベートリソースへのアクセス管理には適さず、この文脈で使うとシステムにオーバーヘッドを加えるだけになると述べています*1。また、循環するリトライアルゴリズムで十分であり依存先がリトライの仕組みを扱えるように設計されている場合は、サーキットブレーカーを追加することが不要な複雑さを生む可能性があるとも指摘しています*1。すべての呼び出しに一律で適用するのではなく、外部サービス呼び出しなど障害の影響が大きい箇所を見極めて適用する判断が必要です。
内製でこれらのパターンを設計・実装するには、分散システムの障害モードに関する理解と、対象サービスごとのパラメータ検証、監視基盤の整備という複数領域の知見が必要になります。自社エンジニアがこの範囲を専任で担えない場合、設計・実装・運用のいずれか、または全体を外部パートナーに委ねる選択肢が検討対象になります。
まとめ:レジリエンス設計を進める3つの判断軸
本稿では、分散システムにおけるカスケード障害の仕組みと、サーキットブレーカー・リトライ・タイムアウト・バルクヘッド・フォールバックという代表的なレジリエンス設計パターンを整理しました。要点を3つに集約すると次の通りです。第一に、これらのパターンはいずれも「一部の障害を全体に波及させない」ことを目的とし、遮断・再試行・隔離・代替応答という異なる役割を分担しています。第二に、パラメータの閾値やタイムアウト時間には一次情報でも固定の推奨値は示されておらず、自社のサービス特性に合わせた検証と監視体制が不可欠です。第三に、複数パターンの多重防御としての組み合わせと、過剰適用を避ける適用範囲の見極めが、設計の質を左右します。
外注する場合の委託範囲と発注準備
レジリエンス設計を外部パートナーに委託する場合、委託範囲は大きく分けて、既存システムの呼び出し経路を洗い出しカスケード障害のリスク箇所を特定する調査・設計フェーズ、サーキットブレーカーやリトライなどのライブラリ導入・実装フェーズ、閾値調整と監視ダッシュボード整備を含む運用定着フェーズの3つに分かれます。発注準備としては、どのサービス間呼び出しを対象とするか、既存の監視基盤(ログ・メトリクス収集の有無)、想定する障害シナリオ(外部API依存か内部マイクロサービス間か)を事前に整理しておくと、委託先とのスコープ合意がしやすくなります。
よくある質問
サーキットブレーカーとリトライは同時に使えますか。
併用できます。Azure Architecture Centerは、サーキットブレーカー経由でリトライパターンを呼び出す構成を挙げています*1。その際、リトライ処理はサーキットブレーカーが返す例外を認識し、障害が一時的でないと示された場合は再試行を止めるように設計する必要があるとされています*1。
バルクヘッドはどのような場合に導入すべきですか。
Azure Architecture Centerは、特定の依存先に対するリソースを分離し、あるサービスの障害がアプリケーション全体に影響しないようにしたい場合や、重要なコンシューマーと標準のコンシューマーを分離したい場合に、この設計を検討すべきだとしています*3。逆に、リソース効率の低下が許容できない場合や、追加の複雑さが不要な場合には適さないとも述べられています*3。
サーキットブレーカーを導入すればカスケード障害を完全に防げますか。
単独では防ぎきれません。Azure Architecture Centerは、外部サービスのタイムアウト時間が長い場合、サーキットブレーカーがアプリケーションを十分に保護できない可能性があると指摘しています*1。タイムアウト・リトライ・バルクヘッドなど他のパターンと組み合わせ、適用範囲を見極めて設計する必要があります。
レジリエンス設計の外注は、どの工程から委託できますか。
呼び出し経路の洗い出しとリスク箇所の特定を行う調査・設計フェーズから委託することも、既存の設計方針を踏まえた実装・運用定着フェーズのみを委託することも可能です。自社の監視基盤の有無や対象範囲によって最適な委託範囲は異なるため、まず現状のシステム構成を整理したうえで相談することをおすすめします。
著者:テレリモ総研編集部 鈴木 亮佑
ご不明な点はお問い合わせフォームからもご連絡いただけます。
- *1 出典:Microsoft「Circuit Breaker pattern – Azure Architecture Center」(learn.microsoft.com)
- *2 出典:Martin Fowler「CircuitBreaker」(martinfowler.com)
- *3 出典:Microsoft「Bulkhead pattern – Azure Architecture Center」(learn.microsoft.com)
- *4 出典:Microsoft「Retry pattern – Azure Architecture Center」(learn.microsoft.com)