バルクヘッドパターン
システムをリソース的に独立した区画に分離し、障害の影響範囲を限定する耐障害性パターン
耐障害性設計パターン
バルクヘッドパターンとは
バルクヘッドパターンは、船舶の隔壁 (バルクヘッド) に着想を得た耐障害性パターンで、システムをリソース的に独立した区画に分離し、障害の影響範囲を限定する。Michael Nygard が「Release It!」(2007 年) で体系化した。
船舶は隔壁で船体を複数の区画に分割しており、1 つの区画に浸水しても他の区画には影響しない。同じ原理をソフトウェアに適用し、1 つのコンポーネントの障害がシステム全体に波及するのを防ぐ。
バルクヘッドがない場合の問題
❌ 共有リソース:
注文 API ─┐
検索 API ─┤→ 共有コネクションプール (100 接続) → DB
通知 API ─┘
検索 API が遅いクエリを大量実行
→ コネクションプールを占有
→ 注文 API と通知 API も接続できなくなる
→ システム全体が停止
分離の方法
| 方法 | 説明 | AWS での実装 |
|---|---|---|
| コネクションプール分離 | サービスごとにプールを分ける | RDS Proxy の複数エンドポイント |
| プロセス分離 | サービスごとに Lambda を分ける | Lambda 関数の分離 |
| キュー分離 | 処理ごとに SQS キューを分ける | SQS キューの分離 |
| 同時実行数の分離 | Lambda の予約済み同時実行数 | ReservedConcurrentExecutions |
| アカウント分離 | ワークロードごとに AWS アカウント | AWS Organizations |
Lambda での実装
Lambda の予約済み同時実行数 (ReservedConcurrentExecutions) はバルクヘッドそのものだ。
# SAM テンプレート
OrderFunction:
Type: AWS::Serverless::Function
Properties:
ReservedConcurrentExecutions: 100 # 注文処理に 100 を確保
SearchFunction:
Type: AWS::Serverless::Function
Properties:
ReservedConcurrentExecutions: 50 # 検索に 50 を確保
NotificationFunction:
Type: AWS::Serverless::Function
Properties:
ReservedConcurrentExecutions: 30 # 通知に 30 を確保
検索 API にトラフィックが集中しても、50 の同時実行数を超えるリクエストはスロットリングされる。注文 API の 100 枠は影響を受けない。
SQS によるキュー分離
注文イベント → 注文キュー (SQS) → 注文処理 Lambda
通知イベント → 通知キュー (SQS) → 通知処理 Lambda
分析イベント → 分析キュー (SQS) → 分析処理 Lambda
キューを分離することで、分析処理が遅延しても注文処理には影響しない。各キューに独立した DLQ (デッドレターキュー) を設定し、障害の追跡も区画ごとに行える。
バルクヘッド vs サーキットブレーカー
| パターン | 目的 | 動作 | タイミング |
|---|---|---|---|
| バルクヘッド | 障害の隔離 | リソースを区画に分離 | 事前 (設計時) |
| サーキットブレーカー | 障害の伝播防止 | 失敗が続いたら呼び出しを停止 | 事後 (障害検知時) |
両方を組み合わせて使うのが効果的だ。バルクヘッドで障害の影響範囲を限定し、サーキットブレーカーで障害が検知された呼び出しを遮断する。
設計時の注意点
- リソースの割り当てを細かくしすぎると、全体の利用効率が下がる。重要度に応じた傾斜配分が現実的
- 区画間の依存関係がある場合、上流の区画が停止すると下流も影響を受ける。依存関係を最小化する設計が重要
- 各区画のリソース使用率をモニタリングし、閾値を超えたらアラートを発報する
より深く学ぶには関連書籍が役立つ。