マイクロサービスへの移行後、「あるサービスが詰まると全体が巻き込まれる」という経験をしたことはないでしょうか。オンプレ時代のモノリシックなシステムでは、CPUやメモリを共有しているのはある意味当然でした。しかしクラウドのマイクロサービス構成では、個別コンポーネントの障害を他に伝播させない設計が生死を分けます。
この記事では、Bulkheadパターン(バルクヘッドパターン)について、その考え方から、AWS上での具体的な実装方法まで現場視点で解説します。サーキットブレーカーとの違い、Lambdaの予約済み同時実行数の使い方、SQSキュー分離の設計指針まで、一通りカバーします。
Bulkheadパターンとは?(船舶設計から来た発想)
Bulkhead(バルクヘッド)とはもともと船舶の防水隔壁を指す言葉です。船が複数の防水区画(コンパートメント)に分割されているように、1つの区画が浸水しても他の区画を守って船全体の沈没を防ぐ構造——これをソフトウェア設計に応用したのがBulkheadパターンです。
オンプレのシステム構成を思い出してください。Webサーバー・APサーバー・DBサーバーが同一筐体または同一ネットワークセグメントにいた時代は、1つのプロセスが暴走してメモリを食い尽くすと、他のプロセスも道連れになりました。クラウドのマイクロサービスでも同じ問題は起きます。むしろ複数サービスが共有スレッドプールや共有コネクションプールを使っていると、1サービスの遅延が全体の応答時間を破壊します。
Bulkheadパターンが解決する問題:
・カスケード障害: 1サービスの詰まりが隣のサービスに伝播する
・リソース枯渇: あるテナントの爆発的なリクエストが他のテナントのリソースを奪う
・スレッド飢餓: バックエンド呼び出しでスレッドプールが埋まり、フロントエンドも応答できなくなる
サーキットブレーカーとの違い
BulkheadとサーキットブレーカーはどちらもResilienceパターンですが、役割が異なります。
| パターン | 発動タイミング | 目的 | 例え |
|---|---|---|---|
| Bulkhead | 常時(リソースを事前に区画分け) | 障害の”爆発半径”を限定する | 防火壁の事前設置 |
| サーキットブレーカー | 障害率が閾値を超えたとき | 障害サービスへの呼び出しを遮断する | 火災検知後に消防車を呼ぶ |
サーキットブレーカーは「火事が起きたら消防車を呼ぶ」、Bulkheadは「そもそも燃え広がらないよう防火壁を設置する」イメージです。両者を組み合わせると、障害を早期に検知して遮断しつつ、万が一遮断が間に合わなかった場合の被害範囲も最小化できます。
サーキットブレーカーの実装についてはサーキットブレーカーパターン入門で詳しく解説しています。
Bulkheadパターンの3つの実装方式
1. スレッドプール分離
アプリケーションレベルで実装する古典的な手法です。外部サービスへの呼び出しごとに専用スレッドプールを割り当てます。Netflix OSSのHystrix(現在はメンテナンスモード)や後継のResilience4jがこれを実現します。
ある呼び出し先が詰まって10スレッドを占有しても、他の呼び出し先は別スレッドプールを使うため影響を受けません。オンプレの頃、JBossやWebLogicのスレッドプールを手動でチューニングしていた経験があるエンジニアには直感的に理解できる概念です。
2. プロセス・コンテナ分離
サービスを独立したプロセス・コンテナとして稼働させ、CPU/メモリのリソース制限を個別に設定します。KubernetesのPodにおけるresources.requestsとresources.limits、ECSのタスク定義のCPU/メモリ設定がこれに相当します。
1つのコンテナがCPUを使い切っても、LinuxのcgroupsによってリソースがOSレベルで分離されているため、他のコンテナは影響を受けません。
3. リソースクォータ分離(テナント・ユーザー単位)
マルチテナントSaaSで特に重要な手法です。特定のテナントや大口ユーザーのリクエストが急増しても、他テナントのリソースを侵食しないようクォータを設定します。API Gatewayの使用量プラン(Usage Plan)やSQSキューの分離がこれに該当します。
AWSでBulkheadパターンを実装する4つの方法
1. AWS Lambda の予約済み同時実行数(Reserved Concurrency)
AWS Lambdaはデフォルトで東京リージョン(ap-northeast-1)のアカウント内の同時実行数の上限(デフォルト1,000)を全関数で共有します。あるLambda関数がバーストして全枠を使い切ると、他の関数が実行できなくなります。
予約済み同時実行数(Reserved Concurrency)を設定すると、特定の関数用に同時実行枠を確保でき、他の関数がその枠を侵食することを防げます。
# AWS CLIで予約済み同時実行数を設定する(東京リージョン) aws lambda put-function-concurrency \ --function-name payment-service \ --reserved-concurrent-executions 100 \ --region ap-northeast-1 # 注文処理サービスは別途50枠を確保 aws lambda put-function-concurrency \ --function-name order-service \ --reserved-concurrent-executions 50 \ --region ap-northeast-1 # 設定確認 aws lambda get-function-concurrency \ --function-name payment-service \ --region ap-northeast-1
注意点: 予約済み同時実行数を設定すると、その関数は指定した枠しか使えなくなります。アカウント全体の上限から「確保分」は他の関数が使えなくなるため、重要度の高いサービスのみに絞って適用するのが現場のベストプラクティスです。
2. Amazon ECS のタスク定義と Capacity Provider による分離
ECSでは、マイクロサービスごとに独立したタスク定義を作成し、CPU/メモリを個別設定します。さらにCapacity Providerを使うと、Fargate Spotと通常Fargateを分けて、バックグラウンド処理は安価なSpotに、フロントエンドは通常Fargateに割り当てる、という区画設計も可能です。
# タスク定義の分離設計例(概念) # 決済サービス: CPU 1024 (1vCPU) / Memory 2048MB → Fargate通常プロバイダー # 注文サービス: CPU 512 (0.5vCPU) / Memory 1024MB → Fargate通常プロバイダー # レポート生成: CPU 256 (0.25vCPU)/ Memory 512MB → Fargate Spotプロバイダー # # → 決済サービスの高負荷がレポート生成の処理に影響しない # → レポート生成がSpotで中断されても決済は安定稼働する
3. Amazon API Gateway の使用量プラン(Usage Plan)
外部APIを公開している場合、APIキー(=テナント/クライアント)ごとにリクエストレートやバースト上限を設定できます。大口クライアントが1秒に数千リクエストを投げても、他のクライアントへの影響を遮断できます。
設定できる項目:
・レート(Throttling Rate): 1秒あたりの最大リクエスト数
・バースト(Throttling Burst): 瞬間的な最大同時リクエスト数
・クォータ(Quota): 日/週/月単位の合計リクエスト上限
APIキーを発行してUsage Planに紐付けるだけで設定できるため、コードの改修なしにテナント単位のBulkheadが実現します。
4. Amazon SQS キューの分離
非同期処理でBulkheadを実現する最もシンプルな手法がSQSキューの分離です。優先度や処理カテゴリごとに別キューを設定し、コンシューマー(LambdaやECSタスク)もキューごとに分けます。
# 優先度別キュー分離の設計例 # 高優先度: payment-queue # → Lambda: payment-consumer(Reserved Concurrency: 50) # # 中優先度: order-queue # → Lambda: order-consumer(Reserved Concurrency: 30) # # 低優先度: report-queue # → Lambda: report-consumer(Reserved Concurrency: 10) # 低優先度のレポート生成キューが数百件積み上がっても、 # payment-consumerの50枠は侵食されない
バッチ処理やレポート生成のような低優先度処理が積み上がっても、決済や注文処理のコンシューマーは別枠で動くため、サービス全体の応答性を守れます。
料金への影響(2026年7月時点)
Bulkheadパターン自体に追加コストは発生しません。ただし、設計の判断によってコストが変わります。
・Lambda の Reserved Concurrency: 設定自体に料金なし。ただし確保した枠が余っていても他の関数は使えないため、アカウント全体のスループット効率が下がる可能性あり。
・ECS のサービス分離: サービスを細かく分けると最小タスク数が増え、Fargateの最低稼働コストが上がる。vCPU 0.25 / Memory 0.5GB構成でも月$8前後(2026年7月時点)はかかるため、細かく分けすぎると固定費が積み上がる。
・SQS キューの追加: キュー数による追加料金なし。リクエスト数課金(最初の100万リクエスト/月は無料、以降$0.40/百万リクエスト、2026年7月時点)のため、キューを増やしても基本コスト増はほぼゼロ。
コスト最適化の観点では、「SLAが厳しいコアサービスのみBulkheadを厳密に適用し、補助的な処理は柔軟に共有リソースを使う」というメリハリ設計が実務では多用されます。
実務Tips・設計指針
区画の軸を設計初期に決める
「サービス単位」「テナント単位」「優先度単位」のどれを区画の軸にするかを、ドメイン設計と同時に決定します。後から追加すると既存コードやインフラ設定の改修が大きくなります。
区画は細かくしすぎない
すべてのサービスに独立したスレッドプールやキューを割り当てると、設定管理・監視ダッシュボード・アラートが爆発的に増えます。SLA・SLO(SLA・SLO・SLIの解説はこちら)を基に、優先度の高いサービスから順番に適用するのが現実的です。
フォールトトレランスとの組み合わせ
Bulkheadは「障害の封じ込め」ですが、フォールトトレランス(フォールトトレランスとHAの違い参照)は「障害の中でも正常に稼働し続ける能力」です。Bulkheadで障害の波及を止め、マルチAZ構成でサービス自体の可用性を高める二段構えが理想的なクラウド設計です。
CloudWatch でBulkheadの効果を可視化する
LambdaのConcurrentExecutionsメトリクスや ECSの CPU/メモリ使用率を、サービスごとにダッシュボードで分離して監視します。あるサービスが予約済み同時実行数の上限に達してスロットリングが始まったら、LambdaはThrottlesメトリクスでアラートを発報します。このアラートをトリガーに、枠の拡大や原因調査に入る運用フローを事前に定めておくと障害対応が格段に速くなります。
オブザーバビリティの設計については監視とオブザーバビリティの違いも参考にしてください。
よくあるトラブルと対処法
「Reserved Concurrencyを設定したらLambdaが全然動かなくなった」
Reserved Concurrencyの値をゼロに設定するとLambdaが完全に無効化されます。最小値は1以上を指定してください。また、アカウントの同時実行上限(デフォルト1,000)から予約済み分を引いた残り枠がゼロになると、他の関数が新たに起動できなくなります。AWS Service Quotasで上限引き上げを申請するか、既存の予約済み設定を見直してください。
「SQSキューを分けたのにコンシューマーが1つで効果が出ない」
キューを分離しても、コンシューマー(Lambda)が1つで両方のキューをポーリングしていると、Bulkheadの効果は半減します。キューごとに独立したLambdaトリガーを設定し、Reserved Concurrencyも別々に割り当てることで初めて区画が成立します。
「Bulkhead適用後に障害が起きてもどの区画が詰まっているかわかりにくい」
区画が増えると監視対象も増えます。CloudWatchのApproximateNumberOfMessagesVisible(SQS)やLambdaのThrottlesをキューごとに集約したダッシュボードを事前に用意しておくと、障害発生時の特定が速くなります。
本記事のまとめ
| ポイント | 内容 |
|---|---|
| Bulkheadの本質 | 障害の爆発半径を限定し、カスケード障害を防ぐ区画設計 |
| サーキットブレーカーとの違い | Bulkheadは「事前の区画設置」、サーキットブレーカーは「障害検知後の遮断」 |
| AWS実装① | Lambda の Reserved Concurrency で同時実行枠をサービス別に分離 |
| AWS実装② | ECS タスク定義の CPU/Memory 制限でコンテナリソースを分離 |
| AWS実装③ | API Gateway の Usage Plan でテナント単位のレートを分離 |
| AWS実装④ | SQS キューの分離 + Lambda トリガー分離で非同期処理を区画化 |
| 設計の注意点 | 区画は細かくしすぎず、SLAを基準に重要度の高いサービスから優先適用する |
Bulkheadパターンは、マイクロサービス化を進めるほど必要性が増す設計思想です。オンプレ時代には「同じサーバーで動いていたから仕方ない」とあきらめていた問題が、クラウドのマネージドサービスと組み合わせることで、コードを書かなくても解決できるケースが増えています。まずはLambda の Reserved Concurrency から始めて、SQSキュー分離へと段階的に適用していくのが現場でのスタートラインです。
PR
Bulkheadを含むクラウドネイティブ設計パターンをAWSサービスと照合しながら体系的に学べる一冊。サーキットブレーカー・Sagaなど本記事の関連パターンもカバーしており、設計フェーズの辞書として手元に置きたい実践的な内容です。
