ひとことで言うと#
1つの障害がシステム全体に波及しないよう、影響範囲(ブラストレディアス)を設計段階から意図的に小さくするパターンの集合。隔壁(バルクヘッド)、サーキットブレーカー、段階的デプロイなどの手法を組み合わせて「壊れても被害を局所化する」アーキテクチャを作る。
押さえておきたい用語#
- ブラストレディアス(Blast Radius)
- 1つの障害やセキュリティインシデントが影響を及ぼす範囲のこと。もとは爆発の影響半径を指す軍事用語。
- バルクヘッド(Bulkhead)
- 船の隔壁に由来する設計パターン。障害を区画内に封じ込め、他の区画に波及させない。スレッドプール分離やサービス分離が典型。
- サーキットブレーカー(Circuit Breaker)
- 下流サービスの障害を検知したら自動的に通信を遮断し、障害の連鎖を防ぐパターン。一定時間後に回復を試みる。
- カナリアリリース(Canary Release)
- 新バージョンをまず全ユーザーの一部(1〜5%)にだけ適用し、問題がなければ段階的に拡大する手法。
- フェイルオーバー(Failover)
- 障害が発生したコンポーネントから正常なコンポーネントに自動的に切り替える仕組み。冗長構成が前提。
ブラストレディアス縮小の全体像#
こんな悩みに効く#
- 1つのサービスの障害が全システムをダウンさせる
- デプロイ直後に問題が起きると全ユーザーが影響を受ける
- 障害が起きるたびに「想定外の波及」で被害が拡大する
- マイクロサービスに分割したのに、障害が連鎖してモノリス以上に脆い
基本の使い方#
各コンポーネントが故障した場合の影響範囲を可視化する。
- システムの依存関係図をベースに、各コンポーネントの「Single Point of Failure」を特定
- 「このDBが落ちたらどの機能が止まるか」を全コンポーネントについて洗い出す
- 影響範囲が広い(ブラストレディアスが大きい)コンポーネントを優先的に対策する
- 依存関係の深さ(何段の連鎖が起きるか)も記録する
障害が波及する経路を物理的・論理的に分離する。
- サービス分離: 重要度の異なる機能を別サービスに分割する
- データ分離: 機能ごとにDBを分け、1つのDB障害が全機能を止めないようにする
- インフラ分離: 重要なサービスを異なるAZ/リージョンに配置する
- スレッドプール分離: 同一プロセス内でも、外部API呼び出し用のスレッドプールを分ける
障害を検知したら自動で対応する仕組みを入れる。
- サーキットブレーカー: 下流の障害を検知したら通信を遮断し、フォールバック応答を返す
- タイムアウト: 全外部通信に適切なタイムアウト値を設定する(デフォルトのまま放置しない)
- グレースフルデグラデーション: 一部の機能が使えなくても、コア機能は動き続けるよう設計する
- カナリアリリース: デプロイの影響範囲を段階的に拡大する
設計した隔壁が本当に機能するか、意図的に障害を注入して検証する。
- Chaos MonkeyやLitmus Chaosなどのツールで障害を注入
- 「サービスAを停止したとき、サービスBは影響を受けないこと」を検証する
- 発見した弱点は修正し、再テストする
- カオステストは定期的(月1回以上)に実施し、新しい依存関係の追加による退行を検出する
具体例#
月間取引30万件のECプラットフォーム。決済代行サービスのAPIが15分間タイムアウトした際、決済処理のスレッドが枯渇し、商品検索や会員ログインまで含めた全機能が停止。影響ユーザー数12万人、損失額約800万円。
障害影響マップの分析: 決済APIのタイムアウトが60秒に設定されており、同時リクエスト300件がスレッドプールを占有。共有スレッドプールだったため、検索やログインのリクエストも処理不能に。
対策:
| 層 | 対策 | 効果 |
|---|---|---|
| 通信層 | 決済APIのタイムアウトを60秒→5秒に短縮 | 長時間のスレッド占有を防止 |
| 通信層 | サーキットブレーカー導入(5回連続失敗でOpen) | 障害検知後1秒で遮断 |
| サービス層 | 決済用スレッドプールを分離(バルクヘッド) | 決済障害が検索に波及しない |
| サービス層 | 決済障害時は「後から決済」モードに縮退 | 注文自体は受付可能 |
導入後、同様の決済APIタイムアウトが発生した際:
- 検索・ログインは影響なし(バルクヘッド効果)
- 決済は5秒後にサーキットブレーカーが作動し、「後から決済」モードに自動切替
- 影響範囲は決済処理中の約200名のみ(全体の0.17%)
- 損失額はほぼゼロ(後から決済で回収)
B2B SaaS(プロジェクト管理ツール)。テナント数800社。ある大手テナントが10万件の一括インポートを実行した際にDBのCPU使用率が98%に張り付き、全テナントのレスポンスが30秒以上に。SLA違反が47社で発生し、信頼を大きく損ねた。
根本原因: 全テナントが同一のDBインスタンスとコネクションプールを共有しており、1テナントの重い処理が全テナントに影響した。
段階的対策:
Phase 1(2週間)— 即効策:
- テナントごとのAPIレートリミット導入(1分あたり1,000リクエスト上限)
- 一括インポートをバックグラウンドジョブキューに移行し、オンラインクエリと分離
- 効果: DB CPU急騰のリスクを即座に緩和
Phase 2(1か月)— バルクヘッド設計:
- DBコネクションプールをテナントサイズ別に3グループに分離(大・中・小)
- 大手テナント(上位20社)は専用のリードレプリカを割り当て
- 効果: 大手テナントの重い処理が中小テナントに影響しない構造に
Phase 3(2か月)— セルアーキテクチャ:
- テナントを4つの「セル」に分割し、各セルが独立したDB・キャッシュ・ワーカーを持つ構成に移行
- 1セルの障害が他の3セルに一切波及しない設計
Phase 3完了後、同規模の一括インポートが発生しても影響範囲は該当セルの200社のみ(全体の25%)。実際にはPhase 2のリードレプリカで吸収され、体感的な影響はゼロだった。
月間PV500万のメディアサイト。全サーバーに一斉デプロイしていたため、デプロイ起因の障害が発生すると全ユーザーが影響を受けていた。直近1年で4回の全体障害が発生し、合計ダウンタイムは7.5時間。
対策: 3段階のカナリアリリース導入
- Stage 1(1%): デプロイ後5分間、エラーレートとレスポンスタイムを自動監視。閾値超過で自動ロールバック
- Stage 2(10%): Stage 1通過後、10%に拡大して10分間監視
- Stage 3(100%): Stage 2通過後、全サーバーに展開
自動ロールバック条件:
- エラーレート: 0.5%超で発動
- レスポンスタイム: 95%ileが500ms超で発動
- メモリ使用量: 80%超で発動
導入後の実績(6か月間):
- Stage 1で自動ロールバックされたデプロイ: 3回(影響ユーザー: 全体の1% = 約1,600人)
- Stage 2で自動ロールバックされたデプロイ: 1回(影響ユーザー: 全体の10% = 約16,000人)
- 全体障害: 0回
従来なら全ユーザー160万人/日が影響を受けていた4回の障害が、カナリアリリースにより影響範囲を平均95%削減。ロールバックも自動なので、オンコール担当の負荷も大幅に軽減された。
やりがちな失敗パターン#
- タイムアウトをデフォルトのまま放置する — 多くのHTTPクライアントのデフォルトタイムアウトは30〜60秒。障害時にスレッドを長時間占有し、被害を拡大させる。全外部通信に適切なタイムアウトを明示的に設定する
- サーキットブレーカーを入れたが閾値が不適切 — 閾値が厳しすぎると正常な一時的エラーで遮断され、緩すぎると障害を通してしまう。本番のエラー率を計測してから設定する
- 分離したつもりが共有リソースが残っている — サービスを分けてもDBやキャッシュが共有のままだと、バルクヘッドの効果が半減する。データ層まで含めて分離計画を立てる
- カオステストをしない — 設計図上は完璧でも、実装漏れや設定ミスは必ずある。実際に障害を注入して「本当に局所化されるか」を定期的に検証する
まとめ#
ブラストレディアス縮小は、「障害は起きる」という前提で、影響範囲を意図的に小さくする設計アプローチ。デプロイ層(カナリアリリース)、通信層(サーキットブレーカー)、サービス層(バルクヘッド)、データ層(DB分離)の4層で多重防御する。1つの障害が全体を止めるシステムは、どれだけ可用性を高めても脆い。壊れたときの被害を小さくすることこそ、本当の耐障害性設計である。