バルクヘッドパターン ばるくへっどぱたーん
障害隔離マイクロサービス耐障害性リソース分離サーキットブレーカーレジリエンス
バルクヘッドパターンについて教えて
簡単に言うとこんな感じ!
船の「防水隔壁(バルクヘッド)」と同じ考え方だよ!船体の一部に穴が開いても、隔壁で区切られた区画が浸水を防いで船全体が沈まないようにする仕組みなんだ。システムも同じで、ある機能が壊れても他の機能に影響が広がらないように「区画分け」する設計パターンってこと!
バルクヘッドパターンとは
バルクヘッドパターン(Bulkhead Pattern) とは、システムの構成要素を意図的に隔離・分割することで、ある部分の障害が他の部分へ波及するのを防ぐ設計パターンです。「バルクヘッド(bulkhead)」とは船舶の防水隔壁のことで、一区画が浸水しても船全体が沈まないように区切る構造から命名されました。
マイクロサービスやクラウドネイティブなシステムでは、サービスが複雑に連携するため、1つのサービスの障害や高負荷が連鎖的に全体へ広がる「カスケード障害」が起きやすくなります。バルクヘッドパターンはこの連鎖を断ち切るために、スレッドプール・接続プール・プロセス・リソース などを機能・サービス単位で分離し、障害の影響範囲を最小化します。
ビジネスの観点では、「一部の機能が重くなっても、注文処理だけは止めない」「外部APIが詰まっても、ログイン機能には影響させない」といった サービスレベルの保証 に直結する重要なパターンです。
バルクヘッドパターンの構造と仕組み
基本的な隔離の単位
| 隔離の単位 | 具体例 | 効果 |
|---|---|---|
| スレッドプール分離 | 機能Aに10スレッド、機能Bに10スレッドを別々に割り当て | 機能Aが全スレッド消費しても機能Bは動き続ける |
| 接続プール分離 | DBへの接続を用途ごとに別プールに分ける | 重いバッチ処理が接続を占有しても参照系は動く |
| プロセス・コンテナ分離 | サービスごとに独立したコンテナ/プロセスを持つ | プロセスクラッシュが他サービスに波及しない |
| ネットワーク分離 | VLANやサブネットで通信経路を区切る | 帯域輻輳の影響範囲を限定できる |
なぜ「隔離しない」と困るのか
【隔離なし:カスケード障害の例】
外部API呼び出し ─── 詰まる!
↓
スレッドが全部埋まる
↓
新しいリクエストも処理できない
↓
注文もログインも検索も全部ダウン ← 全滅!
【隔離あり:バルクヘッドパターン】
外部API用スレッドプール ─── 詰まる!(ここで止まる)
注文処理用スレッドプール ─── 正常稼働中 ✓
ログイン用スレッドプール ─── 正常稼働中 ✓
覚え方:「タコ部屋じゃなくて個室にしろ」
全スレッドが一つの「タコ部屋」に押し込まれていると、一人がコロナになったら全滅。でも「個室」に分けていれば、感染が広がらない。バルクヘッドパターンは リソースを個室化する 設計だと覚えよう!
歴史と背景
- 1800年代: 船舶設計で「防水隔壁(bulkhead)」の概念が確立。タイタニック号はバルクヘッドが不完全で沈没したとも言われ、隔壁設計の重要性が広く認識された
- 2000年代前半: 大規模なモノリシックアプリケーションでは、スレッドプールの枯渇によるシステム全停止が多発。障害隔離の必要性が現場で強く認識されるようになる
- 2011年: Michael T. Nygardが著書 Release It! の中でバルクヘッドを耐障害性パターンの一つとして体系化。エンジニアコミュニティに広まる
- 2012〜2013年: Netflixが Hystrix ライブラリを公開し、スレッドプール分離・サーキットブレーカーをJavaアプリに組み込む実装が普及
- 2015年〜: マイクロサービスアーキテクチャの普及とともに、バルクヘッドパターンはクラウドネイティブ設計の必須知識として定着
- 2020年代: KubernetesのResource Limits/Requests・Istioのトラフィック管理など、インフラレベルでバルクヘッドを実現する手段が標準化
関連パターンとの比較・組み合わせ
バルクヘッドパターンは単独でも使えますが、関連する耐障害性パターンと組み合わせると強力です。
実装例:スレッドプール分離のイメージ(Java/Hystrix風)
// 注文サービス専用のスレッドプール(最大10スレッド)
@HystrixCommand(
threadPoolKey = "orderServicePool",
threadPoolProperties = {
@HystrixProperty(name="coreSize", value="10"),
@HystrixProperty(name="maxQueueSize", value="20")
}
)
public Order getOrder(String orderId) { ... }
// 外部API専用のスレッドプール(最大5スレッド)
@HystrixCommand(
threadPoolKey = "externalApiPool",
threadPoolProperties = {
@HystrixProperty(name="coreSize", value="5")
}
)
public Result callExternalApi() { ... }
// → 外部APIが詰まっても orderServicePool には影響なし!
Kubernetesでのリソース分離(インフラレベルのバルクヘッド)
# 各サービスにCPU/メモリの上限を設けることで
# 1つのPodが暴走しても他のPodへの影響を防ぐ
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi" # ← ここを超えたらOOMKillで隔離
cpu: "500m" # ← ここを超えたらスロットリング
関連用語
- サーキットブレーカーパターン — 障害を検知したら呼び出しを自動的に遮断する耐障害性パターン
- マイクロサービス — サービスを小さな独立した単位に分割するアーキテクチャスタイル
- カスケード障害 — ある障害が連鎖的に広がりシステム全体を停止させる現象
- スレッドプール — 処理を並列実行するためのスレッドをあらかじめ確保しておく仕組み
- レジリエンス — システムが障害から素早く回復・適応できる性質
- タイムアウト — 応答待ちの上限時間を設けてシステムの停滞を防ぐ制御
- リトライパターン — 失敗した処理を自動で再試行する設計パターン
- サービスメッシュ — マイクロサービス間の通信を制御・観測するインフラ層