バルクヘッドパターン

システムをリソース的に独立した区画に分離し、障害の影響範囲を限定する耐障害性パターン

耐障害性設計パターン

バルクヘッドパターンとは

バルクヘッドパターンは、船舶の隔壁 (バルクヘッド) に着想を得た耐障害性パターンで、システムをリソース的に独立した区画に分離し、障害の影響範囲を限定する。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 サーキットブレーカー

パターン 目的 動作 タイミング
バルクヘッド 障害の隔離 リソースを区画に分離 事前 (設計時)
サーキットブレーカー 障害の伝播防止 失敗が続いたら呼び出しを停止 事後 (障害検知時)

両方を組み合わせて使うのが効果的だ。バルクヘッドで障害の影響範囲を限定し、サーキットブレーカーで障害が検知された呼び出しを遮断する。

設計時の注意点

  • リソースの割り当てを細かくしすぎると、全体の利用効率が下がる。重要度に応じた傾斜配分が現実的
  • 区画間の依存関係がある場合、上流の区画が停止すると下流も影響を受ける。依存関係を最小化する設計が重要
  • 各区画のリソース使用率をモニタリングし、閾値を超えたらアラートを発報する

より深く学ぶには関連書籍が役立つ。

関連用語