Azure でのミッション クリティカルなワークロードのアプリケーション設計
アプリケーションを設計するときは、アプリケーションの機能と機能以外の両方の要件が重要です。 この設計領域では、障害に対するアプリケーションの回復性を高めるのに役立つアーキテクチャ パターンとスケーリング戦略について説明します。
重要
この記事は、Azure Well-Architected Framework のミッション クリティカルなワークロード シリーズの一部です。 このシリーズに慣れていない場合は、「ミッション クリティカルなワークロードとは?」から始めることをお勧めします。
スケール ユニット アーキテクチャ
ソリューションのすべての機能面は、需要の変化に合わせてスケーリングできる必要があり、負荷に応じて自動スケーリングするのが理想的です。 スケール ユニット アーキテクチャを使ってコンパートメント化によりエンド ツー エンドのスケーラビリティを最適化することをお勧めし、容量を追加および削除するプロセスを標準化することもお勧めします。 "スケール ユニット" は、独立してスケーリングできる機能の論理的な単位です。 ユニットは、コードのコンポーネント、アプリケーション ホスティング プラットフォーム、関連するコンポーネントをカバーするデプロイ スタンプ、さらにはマルチテナントの要件をサポートするサブスクリプションでも構成できます。
このアプローチを使うと、個々のリソースとアプリケーション全体のスケール制限に対処できるので、お勧めします。 スケール ユニットは 1 つの単位としてデプロイできるため、複雑なデプロイと更新のシナリオに役立ちます。 また、ユニット内のコンポーネントの特定のバージョンを、ユーザー トラフィックをそれに転送する前に、テストして検証することもできます。
ミッション クリティカルなアプリケーションはオンライン製品カタログであるとします。 それには、製品のコメントと評価を処理するためのユーザー フローがあります。 このフローでは、API を使ってコメントと評価の取得と投稿を行い、OAuth エンドポイント、データストア、メッセージ キューなどのサポート コンポーネントを使います。 ステートレス API エンドポイントは、需要の変化に適応する必要がある小さな機能ユニットを表します。 基になるアプリケーション プラットフォームも、それに応じてスケーリングできる必要があります。 パフォーマンスのボトルネックを避けるには、下流のコンポーネントと依存関係も適切なレベルでスケーリングする必要があります。 それらは、独立したスケール ユニットとして個別に、または 1 つの論理ユニットの一部としてまとめて、スケーリングできます。
スケール ユニットの例
次の図は、スケール ユニットにできるスコープを示したものです。 スコープは、マイクロサービス ポッドからクラスター ノードやリージョン単位のデプロイ スタンプまで及びます。
設計上の考慮事項
スコープ: スケール ユニットのスコープ、スケール ユニット間の関係、それらのコンポーネントは、容量モデルに従って定義する必要があります。 パフォーマンスに関する機能以外の要件を考慮します。
スケールの制限: Azure サブスクリプションのスケール制限とクォータが、アプリケーションの設計、テクノロジの選択、スケール ユニットの定義に関係している可能性があります。 スケール ユニットは、サービスのスケール制限を回避するのに役立つことがあります。 たとえば、1 つのユニットの AKS クラスターで保持できるノードが 1,000 個だけの場合、2 つのユニットを使うと、その制限を 2,000 ノードに増やすことができます。
予想される負荷。 ユーザー フローごとの要求の数、予想されるピーク要求レート (1 秒あたりの要求数)、日、週、季節単位のトラフィック パターンを使って、コア スケール要件を表します。 また、トラフィックとデータ ボリューム両方の予想される増加パターンも考慮します。
許容されるパフォーマンス低下。 負荷の下ではサービスが低下して応答時間が長くなっても許容できるかどうかを判断します。 必要な容量をモデル化するときは、負荷の下でソリューションに要求されるパフォーマンスが重要な要素です。
機能以外の要件。 技術とビジネスのシナリオでは、回復性、可用性、待ち時間、容量、監視に関して考慮することが異なります。 これらの要件を、主要なエンド ツー エンドのユーザー フローのコンテキストで分析します。 ユーザー フロー レベルでの設計、意思決定、テクノロジの選択の柔軟性は相対的です。
設計の推奨事項
スケール ユニットのスコープと、ユニットのスケーリングをトリガーする限界を定義します。
すべてのアプリケーション コンポーネントが、独立して、または他の関連コンポーネントを含むスケール ユニットの一部として、スケーリングできることを確認します。
容量モデルと機能以外の要件に基づいて、スケール ユニット間の関係を定義します。
リージョン単位のアプリケーション リソースのプロビジョニング、管理、運用を、種類は異なっていても相互に依存するスケール ユニットに統合するには、リージョン デプロイ スタンプを定義します。 負荷が増加したら、同じまたは異なる Azure リージョン内に追加のスタンプをデプロイして、ソリューションを水平方向にスケーリングできます。
1 つのサブスクリプション内のスケール制限によってスケーラビリティが制約されないように、スケール ユニットとして Azure サブスクリプションを使います。 この方法は、トラフィック量が多い大規模なアプリケーションのシナリオに適用されます。
明らかになったトラフィック パターンを基にして必要な容量をモデル化し、ピーク時に十分な容量がプロビジョニングされてサービスが低下しないようにします。 または、ピーク以外の時間帯の容量を最適化します。
スケールアウトとスケールインの操作に必要な時間を測定し、トラフィックの自然な変動によって許容できないレベルのサービス低下が発生しないようにします。 運用メトリックとしてスケーリング操作の所要時間を追跡します。
Note
Azure ランディング ゾーンにデプロイする場合は、ランディング ゾーンのサブスクリプションをアプリケーション専用にして、明確な管理境界を提供し、うるさい隣人のアンチパターンを回避します。
グローバル配信
高度に分散された環境で障害を回避することは不可能です。 このセクションでは、多くの障害シナリオを軽減する戦略について説明します。 アプリケーションは、リージョンやゾーンの障害に耐えることができる必要があります。 負荷がすべてのリージョンに分散されるように、アクティブ/アクティブ モデルでデプロイする必要があります。
ミッション クリティカルなアプリケーションでの障害に備えて計画を立て、回復性を最大限に高める方法の概要については、こちらのビデオをご覧ください。
設計上の考慮事項
冗長性。 アプリケーションを複数のリージョンにデプロイする必要があります。 さらに、1 つのリージョン内では、可用性ゾーンを使ってデータセンター レベルでのフォールト トレランスに対処することを強くお勧めします。 可用性ゾーン間の待ち時間の上限は 2 ミリ秒未満です。 ゾーン間の "やり取りが多い" ワークロードの場合、この待ち時間のため、ゾーン間データ転送のパフォーマンスが低下する可能性があります。
アクティブ/アクティブ モデル。 可用性を最大にし、より高い複合サービス レベル アグリーメント (SLA) を提供するアクティブ/アクティブ デプロイ戦略をお勧めします。 ただし、多くのアプリケーション シナリオでは、データの同期と一貫性に関する問題が生じる可能性があります。 コストとエンジニアリング作業の増加のトレードオフを考慮しながら、データ プラットフォーム レベルで問題に対処します。
複数のクラウド プロバイダーにまたがるアクティブ/アクティブ デプロイは、1 つのクラウド プロバイダー内のグローバル リソースへの依存が減る可能性のある方法です。 ただし、マルチクラウドのアクティブ/アクティブ デプロイ戦略を採用すると、CI/CD に関する複雑さが大幅に増します。 また、クラウド プロバイダー間のリソースの仕様と機能の違いを考えると、クラウドごとに専用のデプロイ スタンプが必要になります。
地理的な分散。 ワークロードには、地理的なデータ所在地、データ保護、データ保持に関するコンプライアンス要件がある場合があります。 データが存在する必要がある、またはリソースをデプロイする必要がある、特定のリージョンがあるかどうかを検討します。
要求元。 ユーザーまたは依存システムの地理的な近接性と密度が、グローバルな分散に関する設計上の決定に反映される必要があります。
接続性。 ユーザーまたは外部システムがワークロードにアクセスする方法は、設計に影響します。 アプリケーションがパブリック インターネット経由で使用できるか、それとも VPN または Azure ExpressRoute 回線を使用するプライベート ネットワークを介して使用できるかを検討します。
プラットフォーム レベルでの設計の推奨事項と構成の選択については、アプリケーション プラットフォームのグローバル分散に関する記事をご覧ください。
疎結合のイベント駆動型アーキテクチャ
"結合" により、明確に定義されたインターフェイスを介したサービス間通信が可能になります。 "疎" 結合により、アプリケーション コンポーネントは独立して動作できます。 マイクロサービス アーキテクチャ スタイルは、ミッション クリティカルの要件と一致しています。 これは、連鎖的な障害を防いで高可用性を促進します。
疎結合では、イベント駆動型設計を組み込むことを強くお勧めします。 仲介機能を介した非同期メッセージ処理により、回復性を構築できます。
シナリオによっては、ビジネス目標に応じて、アプリケーションで疎結合と密結合を組み合わせることができます。
設計上の考慮事項
ランタイムの依存関係。 疎結合されたサービスは、同じコンピューティング プラットフォーム、プログラミング言語、ランタイム、またはオペレーティング システムを使うように制約されてはなりません。
スケーリング。 サービスは独立してスケーリングできる必要があります。 インフラストラクチャとプラットフォーム リソースの使用を最適化します。
フォールト トレランス。 障害は個別に処理される必要があり、クライアントのトランザクションに影響を与えてはなりません。
トランザクションの整合性。 別のサービスで発生するデータの作成と永続化の影響を検討します。
分散トレース。 エンド ツー エンドのトレースには、複雑なオーケストレーションが必要な場合があります。
設計の推奨事項
マイクロサービスの境界を重要なユーザー フローに合わせます。
可能な場合は、イベント駆動型の非同期通信を使って、持続可能なスケールと最適なパフォーマンスをサポートします。
Outbox や Transactional Session などのパターンを使って一貫性を保証し、すべてのメッセージが正しく処理されるようにします。
例: イベント駆動型アプローチ
Mission-Critical Online 参照実装では、マイクロサービスを使って 1 つのビジネス トランザクションが処理されます。 メッセージ ブローカーとワーカーを使って、書き込み操作が非同期に適用されます。 読み取り操作は同期的であり、結果は呼び出し元に直接返されます。
アプリケーション コードでの回復性パターンとエラー処理
ミッション クリティカルなアプリケーションは、可能な限り多くの障害シナリオに対処する回復性を備えるように設計する必要があります。 この回復性により、サービスの可用性と信頼性が最大になります。 アプリケーションには自己修復機能が必要です。これは、再試行とバックオフやサーキット ブレーカーのような設計パターンを使って実装できます。
アプリケーションのロジックでは完全に軽減できない一時的でない障害の場合、正常性モデルと運用ラッパーで是正措置を実行する必要があります。 正常性モデルに情報を伝え、必要に応じて後続のトラブルシューティングまたは根本原因分析を容易にするため、適切なインストルメンテーションとログをアプリケーション コードに組み込む必要があります。 障害が発生したときに関連付け ID を含む包括的なエラー メッセージを呼び出し元に提供するため、分散トレースを実装する必要があります。
Application Insights のようなツールは、アプリケーションのトレースのクエリ、関連付け、視覚化に役立ちます。
設計上の考慮事項
適切な構成。 一時的な問題が連鎖的な障害を引き起こすのは珍しいことではありません。 たとえば、再試行で適切なバックオフを行わないと、サービスが調整されているときに問題が悪化します。 再試行の遅延を直線的に空けたり、指数関数的に増やしたりして、遅延を長くしながらバックオフできます。
正常性エンドポイント。 外部ソリューションがポーリングしてアプリケーション コンポーネントの正常性状態を取得できる正常性エンドポイントを使って、アプリケーション コード内で機能チェックを公開できます。
設計の推奨事項
回復性のあるアプリケーションのための一般的なソフトウェア エンジニアリング パターンをいくつか次に示します。
Pattern | まとめ |
---|---|
キュー ベースの負荷平準化 | コンシューマーと要求されたリソースの間にバッファーを設けて、読み込みレベルが一定になるようにします。 コンシューマーの要求がキューに入れられると、ワーカー プロセスは、ワーカーと、要求されたリソースの要求処理能力によって設定されるペースで、要求されたリソースに対する要求の処理を行います。 コンシューマーが要求への応答を望む場合は、別の応答メカニズムを実装する必要があります。 最も重要なアクティビティが最初に実行されるように、優先順序を適用します。 |
Circuit Breaker | 回復するまで待つか、使用できないリモート サービスまたはリソースを待つ間ブロックするのではなく要求をすぐに拒否することで、安定性を提供します。 また、このパターンは、リモート サービスまたはリソースへの接続が行われるときの、復旧に要する時間が一定しないエラーも処理します。 |
Bulkhead | 負荷と可用性の要件に基づいてサービス インスタンスをグループに分割し、障害を分離してサービス機能の維持を試みます。 |
Saga | 定義されたイベントまたはメッセージ チャネルを介してサービスが相互に更新されるようにして、独立したデータストアを持つマイクロサービス間のデータ整合性を管理します。 各サービスは、ローカル トランザクションを実行して独自の状態を更新し、saga 内の次のローカル トランザクションをトリガーするイベントを発行します。 サービスの更新が失敗した場合、saga は補正トランザクションを実行してそれ以前のサービス更新手順に対処します。 個々のサービス更新手順では、再試行などの回復性パターンを独自に実装できます。 |
正常性エンドポイント監視 | 公開されたエンドポイントを通じて外部ツールが定期的にアクセスできる機能チェックをアプリケーションに実装します。 主要な運用メトリックを使ってエンドポイントからの応答を解釈し、アプリケーションの正常性を通知して、アラートの生成や補正ロールバック デプロイの実行などの運用応答をトリガーできます。 |
再試行 | 一時的な障害を適切かつ透過的に処理します。 - 障害が一時的である可能性が低く、操作をもう一度試みても成功しそうにない場合はキャンセルします。 - 障害が一般的ではないか、まれなもので、すぐにもう一度試みれば操作が成功する可能性が高い場合は再試行します。 - ネットワーク接続や高負荷の障害など、復旧に短い時間が必要な可能性がある状態により発生した障害の場合は、遅延後に再試行します。 再試行の遅延を増やすときは、適切なバックオフ戦略を適用します。 |
調整 | アプリケーション コンポーネントによって使われるリソースの消費を制御し、負荷が大きくなりすぎないように保護します。 リソースの負荷がしきい値に達したら、優先順位の低い操作を延期し、重要でない機能を低下させて、通常の操作に戻すのに十分なリソースが利用可能になるまで、重要な機能が続行できるようにします。 |
次にいくつかの追加の推奨事項を示します。
Azure SDK などのベンダー提供の SDK を使って、依存サービスに接続します。 カスタム機能を実装する代わりに、組み込みの回復性機能を使います。
失敗した依存関係の呼び出しを再試行するときは適切なバックオフ戦略を適用し、自分の処理によって DDoS シナリオが発生しないようにします。
アプリケーション レベルの回復性パターンの使用の一貫性と速さを高めるため、すべてのアプリケーション マイクロサービス チームに対して共通のエンジニアリング基準を定義します。
C# 用の Polly や Java 用の Sentinel など、定評のある標準化されたパッケージを使って回復性パターンを実装します。
すべてのトレース イベントとログ メッセージに関連付け ID を使って、特定の要求にそれらをリンクします。 失敗した要求だけでなく、すべての呼び出しの呼び出し元に関連付け ID を返します。
すべてのログ メッセージに構造化ログを使います。 アプリケーションのトレース、メトリック、ログに統合された運用データ シンクを選んで、オペレーターが問題を簡単にデバッグできるようにします。 詳しくは、クラウド アプリケーションの監視データの収集、集計、格納に関する記事をご覧ください。
アプリケーション正常性モデルを通知するために、ビジネス要件と共に運用データが使われるようにします。
プログラミング言語の選択
適切なプログラミング言語とフレームワークを選ぶことが重要です。 これらの決定は、多くの場合、組織内のスキル セットまたは標準化されたテクノロジに基づきます。 ただし、さまざまな言語とフレームワークのパフォーマンス、回復性、全体的な機能を評価することが不可欠です。
設計上の考慮事項
開発キットの機能。 さまざまな言語の Azure サービス SDK によって提供される機能には違いがあります。 これらの違いは、Azure サービスまたはプログラミング言語の選択に影響する可能性があります。 たとえば、Azure Cosmos DB が適したオプションである場合、Go はファーストパーティの SDK がないため、適切な開発言語ではない可能性があります。
機能の更新。 選んだ言語の SDK が新機能で更新される頻度を検討します。 .NET や Java ライブラリなどのよく使われる SDK は、頻繁に更新されます。 他の SDK や他の言語の SDK は、更新頻度が低い場合があります。
複数のプログラミング言語またはフレームワーク。 複数のテクノロジを使って、さまざまな複合ワークロードをサポートできます。 ただし、無秩序に広げることは、管理の複雑さと運用上の課題をもたらすので避ける必要があります。
コンピューティング オプション。 レガシまたは独自のソフトウェアは、PaaS サービスで実行されない可能性があります。 また、レガシまたは独自のソフトウェアはコンテナーに格納できない場合もあります。
設計の推奨事項
必要な機能と選んだプログラミング言語について、関連するすべての Azure SDK を評価します。 機能以外の要件との整合性を確認します。
マイクロサービスのレベルで最適なプログラミング言語とフレームワークを選びます。 必要に応じて複数のテクノロジを使います。
信頼性とパフォーマンスを最適にするには .NET SDK を優先します。 通常、.NET Azure SDK はより多くの機能を提供し、頻繁に更新されます。
次のステップ
アプリケーション プラットフォームの考慮事項を確認します。