バルクヘッド パターンは、障害に耐えられるアプリケーション設計の一種です。 バルクヘッド アーキテクチャ ( セル ベースアーキテクチャとも呼ばれます) では、アプリケーションの要素がプールに分離され、障害が発生した場合でも他の要素が引き続き機能します。 バルクヘッドパターンの名前は、船舶の船体にある隔壁(バルクヘッド)に由来します。 船体が傷つけられた場合、水浸しになるのは破損した部分だけで、これによって船が沈むのを防ぎます。
コンテキストと問題
クラウドベースのアプリケーションには複数のサービスが含まれる場合があり、各サービスには 1 つ以上のコンシューマーが含まれます。 サービスの過剰な負荷または障害は、サービスのすべてのコンシューマーに影響します。
また、コンシューマーは複数のサービスに同時に要求を送信し、要求ごとにリソースを使用する場合があります。 コンシューマーが正しく構成されていないサービスまたは応答しないサービスに要求を送信すると、クライアントの要求で使用されるリソースが長期間使用できなくなる可能性があります。 サービスへの要求が続行されると、それらのリソースが使い果たされる可能性があります。 たとえば、クライアントの接続プールが使い果たされている可能性があります。 その時点で、他のサービスに対するコンシューマーの要求が影響を受けます。 最終的に、コンシューマーは、元の応答しないサービスだけでなく、他のサービスに要求を送信することはできません。
リソースの枯渇は、複数のコンシューマーを持つサービスに影響します。 1 つのクライアントからの要求の多くは、サービス内の使用可能なリソースを使い果たす可能性があります。 リソースの枯渇は、他のコンシューマーがサービスを使用できないことを意味し、連鎖的な障害の影響を引き起こす可能性があります。
ソリューション
コンシューマーの負荷と可用性の要件に基づいて、サービス インスタンスを異なるグループにパーティション分割します。 この設計は、障害を分離するのに役立ちます。 障害が発生した場合でも、一部のコンシューマーのサービス機能を維持できます。
コンシューマーは、リソースをパーティション分割して、あるサービスを呼び出すために使用されるリソースが、別のサービスの呼び出しに使用されるリソースに影響しないようにすることもできます。 たとえば、複数のサービスを呼び出すコンシューマーには、サービスごとに接続プールが割り当てられる場合があります。 サービスが失敗し始めた場合、そのサービスに割り当てられている接続プールにのみ影響します。 コンシューマーは引き続き他のサービスを使用できます。
このパターンには次のような利点があります。
コンシューマーとサービスを、障害の連鎖から分離します。 コンシューマーまたはサービスに影響を与える問題は、ソリューション全体が失敗するのを防ぐために、独自のバルクヘッド内で分離できます。
サービスエラーが発生した場合は、一部の機能を保持します。 アプリケーションのその他のサービスと機能は引き続き機能します。
アプリケーションを使用するためのさまざまなサービス レベルの品質を提供します。 優先度の高いサービスを使用するように、優先度の高いコンシューマー プールを構成できます。
次の図は、個々 のサービスを呼び出す接続プールを中心に構造化したバルクヘッドを示しています。 サービス A が失敗した場合、または問題が発生した場合、接続プールは分離されるため、サービス A に割り当てられたスレッド プールを使用するワークロードのみが影響を受けます。 サービス B と C を使用するワークロードは影響を受けず、中断することなく動作を続けることができます。
ワークロード 1 とワークロード 2 の 2 つのワークロードと、サービス A、サービス B、サービス C の 3 つのサービスを示す図。ワークロード 1 では、サービス A に割り当てられている接続プールが使用されます。ワークロード 2 では、2 つの接続プールが使用されます。 1 つの接続プールがサービス B に割り当てられ、もう一方がサービス C に割り当てられます。ワークロード 1 で使用される接続プールは分離されています。 ワークロード 2 で使用される接続プールは、サービス B とサービス C を引き続き呼び出すことができます。
次の図は、1 つのサービスを呼び出す複数のクライアントを示しています。 各クライアントは、個別のサービス インスタンスに割り当てられます。 クライアント 1 が多すぎる要求を行い、そのインスタンスを圧倒します。 各サービス インスタンスは他のサービス インスタンスから分離されているため、他のクライアントは引き続き呼び出しを行うことができます。
クライアント 1、クライアント 2、クライアント 3 の 3 つのクライアントと、それぞれサービス A の一部を形成する 3 つのサービス インスタンスを示す図。各クライアントは、独自のサービス インスタンスに接続します。 サービス インスタンスは分離されています。 クライアント 1 がインスタンスを圧倒した場合、クライアント 2 と 3 は影響を受けません。
問題と考慮事項
このパターンを実装する方法を決定するときは、次の点を考慮してください。
アプリケーションのビジネス要件と技術的要件を中心にパーティションを定義します。
戦術的なドメイン駆動型設計を使用してマイクロサービスを設計する場合、パーティションの境界は境界付けられたコンテキストと一致する必要があります。
サービスまたはコンシューマーをバルクヘッドに分割する場合は、テクノロジによって提供される分離のレベルと、コスト、パフォーマンス、管理容易性の観点からオーバーヘッドを考慮してください。
より高度な障害処理を実現するためには、バルクヘッドと再試行、サーキットブレーカー、スロットリングパターンを組み合わせることを検討してください。
コンシューマーをバルクヘッドにパーティション分割する際は、プロセス、スレッドプール、セマフォの使用を検討してください。 resilience4j や Polly などのプロジェクトが、コンシューマー バルクヘッドを作成するためのフレームワークを提供しています。
サービスをバルクヘッドにパーティション分割する場合は、それらを個別の仮想マシン、コンテナー、またはプロセスにデプロイすることを検討してください。 コンテナーは、かなり少ないオーバーヘッドで、バランスのとれたリソース分離を提供します。
非同期メッセージを使用して通信するサービスは、さまざまなキュー のセットを介して分離できます。 各キューには、キュー上のメッセージを処理するインスタンスの専用セット、またはアルゴリズムを使用して処理をデキューおよびディスパッチするインスタンスの 1 つのグループを含めることができます。
バルクヘッドの細分性のレベルを決定します。 たとえば、複数のパーティションにテナントを分散する場合は、各テナントを個別のパーティションに配置したり、複数のテナントを 1 つのパーティションに配置したりできます。
各パーティションのパフォーマンスとサービス レベル アグリーメント (SLA) を監視します。
Azure API Management のレート制限、Azure Cosmos DB 要求ユニット (RU) の分離、Azure Kubernetes Service (AKS) または Azure Container Apps でのリソース制限など、組み込みのプラットフォーム制御を使用します。 アプリケーション コードでこれらの調整と分離のメカニズムを再作成しないでください。
多くの場合、AI と推論のワークロードでは、デプロイ レベルのクォータとコンカレンシーの制限 (ワークロードごとまたはテナントごとの Azure OpenAI デプロイの分離など) により、厳密なバルクヘッドが必要になります。
このパターンを使用する場合
このパターンは次の状況で使用します。
- 1 つのサービスの中断がアプリケーション全体に影響しないように、特定の依存関係のリソースを分離する必要があります。
- 重要なコンシューマーを標準コンシューマーから分離したいと考えています。
- 連鎖障害からアプリケーションを保護する必要があります。
このパターンは、次の場合に適さない場合があります。
- リソースの効率の低い使用は、プロジェクトで許容できない場合があります。
- 追加の複雑さは必要ありません。
ワークロード設計
ワークロードの設計でバルクヘッド パターンを使用して、 Azure Well-Architected Framework の柱で説明されている目標と原則に対処する方法を評価します。 次の表は、このパターンが各柱の目標をサポートする方法に関するガイダンスを示しています。
| 支柱 | このパターンが柱の目標をサポートする方法 |
|---|---|
| 信頼性設計の決定は、故障に対するワークロードの回復性を高め、障害の発生後にワークロードを完全な機能状態に回復させるために役立ちます。 | コンポーネント間の意図的かつ完全なセグメント化によって導入された障害分離戦略では、問題が発生したバルクヘッドへの障害を含め、他のバルクヘッドへの影響を防ぎます。 - RE:02 重要な流れ - RE:07 自己保護 |
| セキュリティ設計の決定により、ワークロードのデータとシステムの機密性、整合性、および可用性が確保されます。 | コンポーネント間のセグメンテーションは、セキュリティインシデントを侵害されたバルクヘッドに限定するのに役立ちます。 - SE:04 セグメンテーション |
| パフォーマンス効率 は、スケーリング、データ、およびコードの最適化を通じて、ワークロード の需要を効率的に満たすのに役立ちます。 | 各バルクヘッドは個別に拡張可能で、バルクヘッドにカプセル化されたタスクのニーズを効率的に満たすことができます。 - PE:02 容量計画 - PE:05 スケーリングとパーティショニング |
このパターンによって柱内にトレードオフが生じる場合は、他の柱の目標に照らして検討してください。
例
次の Kubernetes 構成ファイルでは、独自の CPU とメモリ リソースと制限で 1 つのサービスを実行する、分離されたコンテナーを作成します。
apiVersion: v1
kind: Pod
metadata:
name: drone-management
spec:
containers:
- name: drone-management-container
image: drone-service
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "1"
次のステップ
- API Management レート制限ポリシーを使用して、クライアントごとの要求スループットを制御します。
- 並列実行を制限するには 、Azure Functions コンカレンシー コントロール を使用します。
- Container Apps リソースの制限を設定して、ワークロードあたりの CPU とメモリを制御します。
- 予測可能な分離のために、コンテナーごとに Azure Cosmos DB RU スループット を割り当てます。