Azure でのミッション クリティカルなワークロードのアプリケーション設計

アプリケーションを設計する場合、機能アプリケーション要件と非機能アプリケーション要件の両方が重要です。 この設計領域では、障害に対するアプリケーションの回復性を高めるのに役立つアーキテクチャ パターンとスケーリング戦略について説明します。

重要

この記事は、Azure Well-Architected Framework ミッション クリティカルなワークロード シリーズの一部です。 このシリーズに慣れていない場合は、「ミッション クリティカルなワークロードとは」から開始することをお勧めします。

スケール ユニット アーキテクチャ

ソリューションのすべての機能面は、需要の変化に合わせてスケーリングできる必要があります。 スケール ユニット アーキテクチャを使用して、コンパートメント化によってエンドツーエンドのスケーラビリティを最適化し、容量の追加と削除のプロセスを標準化することをお勧めします。 スケール ユニットは、個別にスケーリングできる論理ユニットまたは関数です。 ユニットは、コード コンポーネント、アプリケーション ホスティング プラットフォーム、関連コンポーネントを カバーするデプロイ スタンプ 、さらにはマルチテナント要件をサポートするサブスクリプションで構成できます。

個々のリソースとアプリケーション全体のスケール制限に対処するため、この方法をお勧めします。 スケール ユニットは 1 つのユニットとしてデプロイできるため、複雑なデプロイと更新のシナリオに役立ちます。 また、ユーザー トラフィックを転送する前に、ユニット内の特定のバージョンのコンポーネントをテストして検証することもできます。

ミッション クリティカルなアプリケーションがオンライン製品カタログであるとします。 これには、製品のコメントと評価を処理するためのユーザー フローがあります。 このフローでは、API を使用してコメントと評価を取得および投稿し、OAuth エンドポイント、データストア、メッセージ キューなどのサポート コンポーネントを使用します。 ステートレス API エンドポイントは、オンデマンドでの変更に適応する必要がある詳細な機能ユニットを表します。 基になるアプリケーション プラットフォームも、それに応じてスケーリングできる必要があります。 パフォーマンスのボトルネックを回避するには、ダウンストリーム コンポーネントと依存関係も適切な程度にスケーリングする必要があります。 個別のスケール ユニットとして、または 1 つの論理ユニットの一部としてまとめてスケーリングできます。

スケール ユニットの例

次の図は、スケール ユニットで使用できるスコープを示しています。 スコープは、マイクロサービス ポッドからクラスター ノード、リージョンデプロイ スタンプまで多岐に及びます。

スケール ユニットの複数のスコープを示す図。

設計上の考慮事項

  • スコープ: スケール ユニットのスコープ、スケール ユニット間のリレーションシップ、およびそれらのコンポーネントは、容量モデルに従って定義する必要があります。 パフォーマンスに関する機能以外の要件を考慮してください。

  • スケールの制限: Azure サブスクリプションのスケール制限とクォータ は、アプリケーションの設計、テクノロジの選択、スケール ユニットの定義に影響を及ぼしている可能性があります。 スケール ユニットは、サービスのスケール制限をバイパスするのに役立ちます。 たとえば、1 つのユニット内の AKS クラスターに含めることができるノードが 1,000 個しかない場合は、2 つのユニットを使用して、その制限を 2,000 ノードに増やすことができます。

  • 予想される負荷。 コア スケール要件を通知するには、各ユーザー フローの要求数、予想されるピーク要求レート (1 秒あたりの要求数)、毎日/毎週/季節のトラフィック パターンを使用します。 また、トラフィックとデータ ボリュームの両方で予想される増加パターンも考慮します。

  • 許容されるパフォーマンス低下。 応答時間の長い低下したサービスが負荷の下で許容できるかどうかを判断します。 必要な容量をモデル化する場合、負荷がかかっているソリューションの必要なパフォーマンスが重要な要素になります。

  • 機能しない要件。 技術的なシナリオとビジネス シナリオには、回復性、可用性、待機時間、容量、可観測性に関する個別の考慮事項があります。 これらの要件を、主要なエンド ツー エンド ユーザー フローのコンテキストで分析します。 ユーザー フロー レベルでの設計、意思決定、テクノロジの選択には相対的な柔軟性があります。

設計の推奨事項

  • スケール ユニットのスコープと、スケールするユニットをトリガーする制限を定義します。

  • すべてのアプリケーション コンポーネントが、独立して、または他の関連コンポーネントを含むスケール ユニットの一部としてスケーリングできることを確認します。

  • 容量モデルと非機能要件に基づいて、スケール ユニット間の関係を定義します。

  • リージョン デプロイ スタンプを定義して、リージョン アプリケーション リソースのプロビジョニング、管理、運用を異種の相互依存スケール ユニットに統合します。 負荷が増加すると、同じ Azure リージョン内または異なるリージョン内に追加のスタンプをデプロイして、ソリューションを水平方向にスケーリングできます。

  • 1 つのサブスクリプション内のスケール制限によってスケーラビリティが制約されないように、スケール ユニットとして Azure サブスクリプションを使用します。 この方法は、トラフィック量が多い大規模なアプリケーション シナリオに適用されます。

  • サービスの低下を防ぐために、ピーク時に十分な容量がプロビジョニングされるように、識別されたトラフィック パターンに関する必要な容量をモデル化します。 または、ピーク時以外の時間帯に容量を最適化します。

  • スケールアウト操作とスケールイン操作の実行に必要な時間を測定して、トラフィックの自然な変動によって許容できないレベルのサービス低下が生じないようにします。 操作メトリックとしてスケール操作の期間を追跡します。

Note

Azure ランディング ゾーンにデプロイする場合は、ランディング ゾーン サブスクリプションがアプリケーション専用であることを確認して、明確な管理境界を提供し、ノイズの多い近隣のアンチパターン回避します。

グローバル配信

高度に分散された環境で障害を回避することは不可能です。 このセクションでは、多くの障害シナリオを軽減する方法について説明します。 アプリケーションは、地域およびゾーンの障害に耐えることができる必要があります。 負荷がすべてのリージョンに分散されるように、アクティブ/アクティブ モデルにデプロイする必要があります。

ミッション クリティカルなアプリケーションで障害を計画し、回復性を最大限に高める方法の概要については、このビデオをご覧ください。

設計上の考慮事項

  • 冗長性。 アプリケーションを複数のリージョンにデプロイする必要があります。 さらに、リージョン内では、データセンター レベルでフォールト トレランスを可能にするために可用性ゾーンを使用することを強くお勧めします。 可用性ゾーンの待機時間の境界は、可用性ゾーン間で 2 ミリ秒未満です。 ゾーン間で "おしゃべり" なワークロードの場合、この待機時間により、ゾーン間データ転送のパフォーマンスが低下する可能性があります。

  • アクティブ/アクティブ モデル。 アクティブ/アクティブデプロイ戦略は、可用性を最大化し、より高い複合サービス レベル アグリーメント (SLA) を提供するため、推奨されます。 ただし、多くのアプリケーション シナリオでは、データの同期と一貫性に関する課題が生じる可能性があります。 コストの増加とエンジニアリング作業のトレードオフを考慮しながら、データ プラットフォーム レベルで課題に対処します。

    複数のクラウド プロバイダー間でのアクティブ/アクティブデプロイは、1 つのクラウド プロバイダー内のグローバル リソースへの依存関係を軽減する可能性のある方法です。 ただし、マルチクラウドのアクティブ/アクティブデプロイ戦略では、CI/CD に関してかなりの複雑さが発生します。 また、クラウド プロバイダー間のリソース仕様と機能の違いを考えると、クラウドごとに特殊なデプロイ スタンプが必要になります。

  • 地理的分布。 ワークロードには、地理的なデータ所在地、データ保護、およびデータ保持に関するコンプライアンス要件がある場合があります。 データが存在する必要がある特定のリージョンがあるか、リソースをデプロイする必要があるかを検討します。

  • 要求元。 ユーザーまたは依存システムの地理的近接性と密度は、グローバル分散に関する設計上の決定を通知する必要があります。

  • 接続性。 ユーザーまたは外部システムがワークロードにアクセスする方法は、設計に影響します。 アプリケーションがパブリック インターネット経由で使用できるか、VPN または Azure ExpressRoute 回線を使用するプライベート ネットワークを介して使用できるかを検討します。

プラットフォーム レベルでの設計の推奨事項と構成の選択については、「アプリケーション プラットフォーム: グローバル分散」を参照してください

疎結合のイベント ドリブン アーキテクチャ

結合 により、適切に定義されたインターフェイスを介したサービス間通信が可能になります。 結合により、アプリケーションコンポーネントは独立して動作できます。 マイクロサービス アーキテクチャ スタイルは、ミッション クリティカルな要件と一致しています。 これは、連鎖的な障害を防ぐことによって高可用性を促進します。

疎結合の場合は、イベントドリブン設計を組み込むことを強くお勧めします。 仲介者を介した非同期メッセージ処理は、回復性を構築できます。

非同期のイベント ドリブン通信を示す図。

一部のシナリオでは、ビジネス目標に応じて、アプリケーションで疎結合と密結合を組み合わせることができます。

設計上の考慮事項

  • ランタイムの依存関係。 疎結合のサービスは、同じコンピューティング プラットフォーム、プログラミング言語、ランタイム、またはオペレーティング システムを使用するように制限しないでください。

  • スケーリング。 サービスは個別にスケーリングできる必要があります。 インフラストラクチャとプラットフォーム リソースの使用を最適化します。

  • フォールト トレランス。 エラーは個別に処理する必要があり、クライアント トランザクションには影響しません。

  • トランザクションの整合性。 個別のサービスで発生するデータの作成と永続化の影響を考慮してください。

  • 分散トレース。 エンドツーエンドのトレースでは、複雑なオーケストレーションが必要になる場合があります。

設計の推奨事項

  • マイクロサービスの境界を重要なユーザー フローに合わせます。

  • 可能な場合は、イベントドリブンの非同期通信を使用して、持続可能なスケールと最適なパフォーマンスをサポートします。

  • すべてのメッセージが正しく処理されるように一貫性を保証するには、送信トレイやトランザクション セッションなどのパターンを使用します。

例: イベント ドリブンアプローチ

Mission-Critical Online の参照実装では、マイクロサービスを使用して 1 つのビジネス トランザクションを処理します。 メッセージ ブローカーと worker を使用して、書き込み操作を非同期的に適用します。 読み取り操作は同期的であり、結果は呼び出し元に直接返されます。

イベントドリブン通信を示す図。

アプリケーション コードでの回復性パターンとエラー処理

ミッション クリティカルなアプリケーションは、可能な限り多くの障害シナリオに対処できるように回復性を備えるように設計する必要があります。 この回復性により、サービスの可用性と信頼性が最大化されます。 アプリケーションには自己復旧機能が必要です。これは、バックオフサーキット ブレーカーを使用した再試行などの設計パターンを使用して実装できます。

アプリケーション ロジックで完全に軽減できない一時的でない障害の場合、正常性モデルと運用ラッパーは是正措置を取る必要があります。 アプリケーション コードには、正常性モデルに通知し、必要に応じて後続のトラブルシューティングまたは根本原因分析を容易にするために、適切なインストルメンテーションとログを組み込む必要があります。 障害発生時に関連付け ID を含む包括的なエラー メッセージを呼び出し元に提供するには、分散トレースを実装する必要があります。

アプリケーション インサイトなどのツールは、アプリケーション トレースのクエリ、関連付け、視覚化に役立ちます。

設計上の考慮事項

  • 適切な構成。 一時的な問題が連鎖的な障害を引き起こすのは珍しいことではありません。 たとえば、適切なバックオフなしで再試行すると、サービスが調整されているときに問題が悪化します。 再試行の遅延を直線的に間隔を空けたり、増加する遅延によってバックオフするように指数関数的に遅延を増やしたりすることができます。

  • 正常性エンドポイント。 外部ソリューションがポーリングしてアプリケーション コンポーネントの正常性状態を取得できる正常性エンドポイントを使用して、アプリケーション コード内で機能チェックを公開できます。

設計の推奨事項

回復性のある アプリケーションの一般的なソフトウェア エンジニアリング パターンを 次に示します。

Pattern まとめ
キュー ベースの負荷平準化 一貫性のある読み込みレベルを確保するために、コンシューマーと要求されたリソースの間にバッファーを導入します。 コンシューマー要求がキューに登録されると、ワーカー プロセスは、要求されたリソースに対して、worker によって設定されたペースで、要求されたリソースに対して、要求を処理する要求されたリソースの能力によって処理されます。 コンシューマーが要求に対する応答を期待する場合は、別の応答メカニズムを実装する必要があります。 最も重要なアクティビティが最初に実行されるように、優先順位付けされた順序を適用します。
Circuit Breaker 回復を待機するか、使用できないリモート サービスまたはリソースを待機している間にブロックするのではなく、要求を迅速に拒否することで、安定性を提供します。 また、このパターンでは、リモート サービスまたはリソースへの接続が確立されたときに、復旧に可変の時間がかかる可能性があるエラーも処理します。
Bulkhead 負荷と可用性の要件に基づいてサービス インスタンスをグループにパーティション分割し、サービス機能を維持するための障害を分離しようとします。
Saga 定義されたイベントまたはメッセージ チャネルを介してサービスが相互に更新されるようにすることで、独立したデータストアを持つマイクロサービス間のデータ整合性を管理します。 各サービスは、ローカル トランザクションを実行して独自の状態を更新し、saga で次のローカル トランザクションをトリガーするイベントを発行します。 サービスの更新が失敗した場合、saga は、前のサービス更新手順に対処するために補正トランザクションを実行します。 個々のサービス更新手順では、再試行などの回復性パターンを実装できます。
正常性エンドポイント監視 外部ツールが一定の間隔で公開されたエンドポイントを介してアクセスできる機能チェックをアプリケーションに実装します。 主要な運用メトリックを使用してアプリケーションの正常性を通知し、アラートの発生やロールバックの補正デプロイの実行などの運用応答をトリガーすることで、エンドポイントからの応答を解釈できます。
再試行 一時的な障害をエレガントかつ透過的に処理します。
- 障害が一時的である可能性が低く、操作が再度試行された場合に成功する可能性が低い場合はキャンセルします。
- 障害が異常またはまれで、すぐにもう一度試行した場合に操作が成功する可能性が高い場合は再試行します。
- ネットワーク接続や高負荷の障害など、復旧に短時間が必要な状態が原因で障害が発生した場合は、遅延後に再試行します。 再試行の遅延が増加するにつれて、適切なバックオフ戦略を適用します。
調整 アプリケーション コンポーネントによって使用されるリソースの消費を制御し、過剰にエンカンバリングされないように保護します。 リソースが負荷のしきい値に達すると、優先順位の低い操作が延期され、重要でない機能が低下するため、通常の操作に戻るために十分なリソースが使用可能になるまで、重要な機能を続行できます。

次にいくつかの追加の推奨事項を示します。

  • 依存サービスに接続するには、Azure SDK などのベンダー提供の SDK を使用します。 カスタム機能を実装する代わりに、組み込みの回復性機能を使用します。

  • 失敗した依存関係呼び出しを再試行するときに適切なバックオフ戦略を適用して、自傷の DDoS シナリオを回避します。

  • すべてのアプリケーション マイクロサービス チームに共通のエンジニアリング基準を定義して、アプリケーション レベルの回復性パターンの使用における一貫性と速度を促進します。

  • Polly for C# や Sentinel for Java など、実証済みの標準化されたパッケージを使用して回復性パターンを実装します。

  • すべてのトレース イベントとログ メッセージに関連付け ID を使用して、特定の要求にリンクします。 失敗した要求だけでなく、すべての呼び出しの呼び出し元に関連付け ID を返します。

  • すべてのログ メッセージに構造化ログを使用します。 アプリケーション トレース、メトリック、およびログの統合された運用データ シンクを選択して、オペレーターが問題を簡単にデバッグできるようにします。 詳細については、「クラウド アプリケーションの監視データの収集、集計、および格納」を参照してください

  • 運用データがビジネス要件と共に使用され、アプリケーションの正常性モデル通知されることを確認します。

プログラミング言語の選択

適切なプログラミング言語とフレームワークを選択することが重要です。 これらの決定は、多くの場合、組織内のスキル セットまたは標準化されたテクノロジによって推進されます。 ただし、さまざまな言語とフレームワークのパフォーマンス、回復性、および全体的な機能を評価することが不可欠です。

設計上の考慮事項

  • 開発キットの機能。 さまざまな言語で Azure サービス SDK によって提供される機能には違いがあります。 これらの違いは、Azure サービスまたはプログラミング言語の選択に影響する可能性があります。 たとえば、Azure Cosmos DB が実行可能なオプションである場合、Go はファーストパーティ SDK がないため、適切な開発言語ではない可能性があります。

  • 機能の更新。 選択した言語の新機能で SDK を更新する頻度を検討します。 .NET や Java ライブラリなど、一般的に使用される SDK は頻繁に更新されます。 他の言語の他の SDK または SDK は、更新頻度が低い場合があります。

  • 複数のプログラミング言語またはフレームワーク。 複数のテクノロジを使用して、さまざまな複合ワークロードをサポートできます。 ただし、管理の複雑さと運用上の課題が生じるので、スプロールを避ける必要があります。

  • コンピューティング オプション。 PaaS サービスでは、レガシ ソフトウェアまたはプロプライエタリ ソフトウェアが実行されない場合があります。 また、従来のソフトウェアや独自のソフトウェアをコンテナーに含めることができない場合もあります。

設計の推奨事項

  • 必要な機能と選択したプログラミング言語について、関連するすべての Azure SDK を評価します。 機能していない要件との整合性を確認します。

  • マイクロサービス レベルでプログラミング言語とフレームワークの選択を最適化します。 必要に応じて複数のテクノロジを使用します。

  • 信頼性とパフォーマンスを最適化するために、.NET SDK に優先順位を付けます。 .NET Azure SDK は通常、より多くの機能を提供し、頻繁に更新されます。

次のステップ

アプリケーション プラットフォームの考慮事項を確認します。