この記事では、要求の非同期処理やソリューション内で高スループットを実現する方法など、ミッション クリティカルなアプリケーションの信頼性と回復性の側面について説明します。 この記事シリーズでは、ユーザーがアイテムのカタログを参照し、アイテムの詳細を確認し、アイテムの評価とコメントを投稿できる、信頼性の高いワークロードの例として、単純なオンライン カタログ シナリオを使用します。
アプリケーションの構成
大規模でミッション クリティカルなアプリケーションでは、エンドツーエンドのスケーラビリティと回復性のためにアーキテクチャを最適化することが不可欠です。 コンポーネントは、独立して動作できる機能単位に分離できます。 アプリケーション スタックのすべてのレベルでこの分離を適用して、システムの各部分を独立してスケーリングし、需要の変化に対応できるようにします。
アプリケーションでステートレス API エンドポイントを使用すると、実行時間の長い書き込み要求がメッセージング ブローカーを介して非同期的に分離されます。 ワークロードの構成を使用すると、Azure Kubernetes Service (AKS) クラスター全体と、スタンプ内の他の依存関係をいつでも削除して再作成できます。 アプリケーションの主要コンポーネントを次に示します。
ユーザー インターフェイス (UI):ユーザーがアクセスできるシングルページ Web アプリケーション。 UI は、Azure Storage アカウントの静的 Web サイト ホストとしてホストされます。
API (
CatalogService): UI アプリケーションが呼び出す REST API。ただし、他の潜在的なクライアント アプリケーションにも使用できます。Worker (
BackgroundProcessor): メッセージ バスの新しいイベントをリッスンし、データベースへの書き込みリクエストを処理するバックグラウンド ワーカー。 このコンポーネントは API を公開しません。正常性サービス API (
HealthService): データベースやメッセージング バスなど重要なコンポーネントが動作しているかを確認し、アプリケーションの正常性を報告する API。
ワークロードは、API、ワーカー、正常性チェックアプリケーションで構成されています。 コンテナとしてワークロードをホストする workload という専用 AKS 名前空間。 ポッド間の直接通信は発生しません。 ポッドはステートレスで、独立して拡張できます。
クラスタで実行されているその他の対応コンポーネントは、以下のとおりです。
NGINX イングレス コントローラー: 受信リクエストをワークロードにルーティングし、ポッド間での負荷を分散します。 NGINX イングレス コントローラーは、パブリック IP アドレスを持つ Azure Load Balancer を経由して公開されますが、Azure Front Door を介してのみアクセスできます。
証明書マネージャー: Jetstack のシステムは、イングレスルールに対して Let's Encrypt を利用して Transport Layer Security (TLS) 証明書を自動的にプロビジョニングします。
Secrets Store CSI Driver: Secrets Store CSI Driver 向け Azure Key Vault プロバイダは、Key Vault からの接続文字列などのシークレットを安全に読み取ります。
監視エージェント: デフォルトの OMSAgentForLinux 構成は、Azure Monitor Logs ワークスペースに送信される監視データ量を減らすために調整されます。
データベース接続
デプロイ スタンプは一時的なものであるため、状態をスタンプ内に保持することはできるだけ避けます。 状態は、外部化されたデータ ストアで保持します。 信頼性サービス レベル目標 (SLO) をサポートするには、回復性のあるデータ ストアを作成します。 マネージドまたは Platform as a Service (PaaS) 、ソリューションを、タイムアウト、切断、その他エラー状態を自動で処理するネイティブ SDK ライブラリと組み合わせて使用することが推奨されます。
Azure Cosmos DB は、アプリケーションのメイン データ ストアとして機能します。 Azure Cosmos DB では、複数リージョンの書き込みが可能です。 各スタンプは、同じリージョン内の Azure Cosmos DB レプリカに書き込むことができ、リージョン間のデータ レプリケーションと同期が Azure Cosmos DB によって内部的に処理されます。 Azure Cosmos DB for NoSQL では、データベース エンジンのすべての機能がサポートされています。
詳細については、「ミッション クリティカルなワークロードのデータ プラットフォーム」を参照してください。
注記
新しいアプリケーションでは、Azure Cosmos DB for NoSQL を使用します。 別の NoSQL プロトコルを使用するレガシ アプリケーションの場合は、Azure Cosmos DB への移行パスを評価します。
パフォーマンスよりも可用性を優先するミッション クリティカルなアプリケーションの場合は、厳密な整合性レベルの 単一リージョンの書き込みと複数リージョンの読み取りが推奨されます。
Azure Storage を使用して、Azure Event Hubs チェックポイント処理のスタンプに状態を一時的に格納します。
ワークロード コンポーネントはすべて、Azure Cosmos DB .NET Core SDK を使用して、データベースと通信します。 SDK には、データベース接続を維持し、障害を処理するための堅牢なロジックが用意されています。 主要な構成設定は次のとおりです。
直接接続モード: この設定は、パフォーマンスが向上するため、.NET SDK v3 の既定値です。 直接接続モードでは、HTTP を使用するゲートウェイ モードと比較して、ネットワーク ホップが少なくなります。
書き込み時にコンテンツ応答を返す: このアプローチは、Azure Cosmos DB クライアントが、ネットワーク トラフィックを削減する作成、アップサート、パッチ、置換操作からドキュメントを返すことができないため、無効になっています。 クライアントでの追加処理では、この設定は必要ありません。
カスタム シリアル化: このプロセスでは、
JsonNamingPolicy.CamelCaseが .NET プロパティを標準の JSON プロパティに変換するように JSON プロパティの名前付けポリシーを設定します。 また、JSON プロパティを .NET プロパティに変換することもできます。 既定の無視条件により、シリアル化中は、JsonIgnoreCondition.WhenWritingNullのような Null 値を持つプロパティは無視されます。ApplicationRegion: このプロパティはスタンプのリージョンに設定されます。これにより、SDK は最も近い接続エンドポイントを検索できます。 エンドポイントは、同じリージョンにすることが推奨されます。
非同期メッセージング
疎結合を実装する場合、サービスは他のサービスに依存しません。 疎結合の特徴により、サービスは独立して動作できます。 結合の特徴により、明確に定義されたインターフェイスを介したサービス間通信が可能になります。 ミッション クリティカルなアプリケーションの場合、疎結合により、ダウンストリームの障害がフロントエンドやその他のデプロイ スタンプにカスケードするのを防ぎ、高可用性を実現します。
非同期メッセージングの主な特徴は次のとおりです。
サービスは、同じコンピューティング プラットフォーム、プログラミング言語、またはオペレーティング システムを使用する必要はありません。
サービスは独立してスケーリングします。
ダウンストリームの障害がクライアント トランザクションに影響しません。
データの作成と永続化が別々のサービスで行われるため、トランザクションの整合性を維持することはより困難です。 トランザクションの整合性は、メッセージング サービスと永続化サービス全体の課題です。 詳細については、「Idempotent message processing」を参照してください。
エンドツーエンドのトレースには、複雑なオーケストレーションが必要です。
Queue-Based Load Leveling pattern や Competing Consumers pattern などよく知られている設計パターンの使用が推奨されます。 これらのパターンは、プロデューサーからコンシューマーへの負荷を分散し、コンシューマーによる非同期を処理します。 たとえば、ワーカーは、API で要求を受け入れて呼び出し元にすばやく返し、ワーカーがデータベースの書き込み操作を個別に処理するようにします。
Event Hubs は、API とワーカー間のメッセージを仲介します。
重要
メッセージ ブローカーは、長期間にわたる永続的なデータ ストアとして使用しないでください。 Event Hubs サービスでは、キャプチャ機能がサポートされています。 キャプチャ機能を使用すると、イベント ハブは、リンクされたストレージ アカウントにメッセージのコピーを自動的に書き込むことができます。 このプロセスは、メッセージをバックアップするメカニズムとして使用状況とサービスを制御します。
書き込み操作の実装の詳細
評価の投稿やコメントの投稿などの書き込み操作は非同期的に処理されます。 最初に、API から、アクションの種類やコメント データなど、すべての関連情報を含むメッセージがメッセージ キューに送信され、作成されるオブジェクトの HTTP 202 (Accepted) ヘッダーを含む Location がすぐに返されます。
BackgroundProcessor インスタンスはキュー内のメッセージを処理し、書き込み操作のための実際のデータベース通信を行います。
BackgroundProcessor が、キュー上のメッセージ ボリュームに基づいて動的にスケールインおよびスケールアウトします。 プロセッサ インスタンスのスケールアウト制限は、Event Hubs パーティションの最大数 (Basic レベルと Standard レベルでは 32、プレミアム レベルでは 100、専用レベルでは 1024) によって定義されます。
BackgroundProcessor の Azure Event Hubs プロセッサ ライブラリは、Azure Blob Storage を使用して、パーティションの所有権、さまざまなワーカー インスタンス間の負荷分散を管理し、チェックポイントを使用して進行状況を追跡します。 チェックポイントは、すべてのメッセージに高価な遅延を追加するため、すべてのイベントの後に Blob Storage に書き込まれることはありません。 代わりに、チェックポイントはタイマー ループに書き込まれ、期間を構成できます。 既定の設定は 10 秒です。
プロセッサ アプリケーションでエラーが発生した場合や、メッセージを処理する前に停止した場合は、次のようになります。
別のインスタンスが再処理のためにメッセージを取得します。これは、Storage 内にチェックポイントが適切に設定されなかったためです。
競合は、ワーカーが失敗する前に、以前のワーカーがドキュメントをデータベースに保存した場合に発生します。 このエラーは、同じ ID とパーティション キーが使用されるために発生します。 ドキュメントは既に永続化されているため、プロセッサはメッセージを無視しても問題ありません。
以前のワーカーがデータベースに書き込む前に終了した場合、新しいインスタンスは、手順を繰り返して、永続化を最終化します。
操作の実装の詳細を読み取る
API は直接読み取り操作を処理し、すぐにユーザーにデータを返します。
操作が正常に完了した場合、クライアントと通信するためのバックチャネル メソッドは確立されません。 クライアント アプリケーションから、Location HTTP ヘッダーに指定された項目の更新に対して API を事前にポーリングする必要があります。
スケーラビリティ
個々のワークロード コンポーネントは、それぞれのコンポーネントのロード パターンが異なるため、独立してスケールアウトする必要があります。 スケーリング要件は、サービスの機能によって異なります。 特定のサービスはユーザーに直接影響し、迅速な応答と肯定的なユーザー エクスペリエンスを確保するために積極的にスケールアウトする必要があります。
サービスをコンテナー イメージとしてパッケージ化し、Helm チャートを使用して各スタンプにサービスをデプロイします。 サービスは、予想される Kubernetes の要求と制限、事前構成済みの自動スケーリング規則が適用されるように構成されます。
CatalogService と BackgroundProcessor のワークロード コンポーネントは、どちらのサービスもステートレスなので、個別にスケールインおよびスケールアウトできます。
ユーザーが直接 CatalogService を操作するため、ワークロードのこの部分はどのような負荷でも応答する必要があります。 各クラスターには、少なくとも 3 つのインスタンスがあり、Azure リージョンで 3 つの Availability Zone を分散します。 AKS の水平ポッド オートスケーラー (HPA) では、必要に応じてポッドが自動的に追加されます。 Azure Cosmos DB オートスケール機能では、コレクションで使用できる要求ユニット (RU) を動的に増減できます。
CatalogService と Azure Cosmos DB を組み合わせて、スタンプ内にスケール ユニットを形成します。
HPA は、レプリカの最大数と最小数を構成可能な Helm チャートを使ってデプロイされます。 ロード テストでは、各インスタンスが標準の使用パターンで 1 秒あたり約 250 件の要求を処理できることを確認しました。
BackgroundProcessor サービスには非常に異なる要件があり、ユーザー エクスペリエンスへの効果が限られているバックグラウンド ワーカーと見なされます。 そのため BackgroundProcessor は、CatalogService と比較して、異なるオートスケール構成があり、2 から 32 のインスタンス間でスケーリングできます。 イベント ハブで使用するパーティション数に基づいて、この制限を決定します。 パーティションよりも多くのワーカーは必要ありません。
| コンポーネント | minReplicas |
maxReplicas |
|---|---|---|
| カタログサービス | 3 | 20 |
| バックグラウンドプロセッサー | 2 | 32 |
ingress-nginx などの依存性を含むワークフローの各コンポーネントには、 ポッド中断バジェット (PDB) があり、クラスターが変更された際に使用できるインスタンスの最小数を確保するよう設定が構成されています。
注記
Load Testing を介して、各コンポーネントのポッドの実際の最小数と最大数を決定します。
インストルメンテーション
インストルメンテーションを使用して、ワークロード コンポーネントがシステムにもたらす可能性のあるパフォーマンスのボトルネックと正常性の問題を評価します。 数量を決定するため、各コンポーネントはメトリックとトレース ログを介して十分な情報を出力する必要があります。 アプリケーションをインストルメント化する際は、次の重要事項を考慮してください。
- ログ、メトリック、別のテレメトリをスタンプのログ システムに送信します。
- 情報をクエリできるように、プレーン テキストではなく、構造化ログを使用します。
- イベントの相関関係を実装して、エンドツーエンドのトランザクション ビューを取得します。 たとえば、すべての API 応答には、追跡可能な HTTP ヘッダーとして操作 ID が含まれています。
- stdout ロギングまたはコンソール ロギングのみに依存しないでください。 ただし、これらのログを使用すると、障害が発生したポッドのトラブルシューティングをすぐに行うことができます。
Application Insights と、アプリケーション監視データ用の Azure Monitor ログ ワークスペースを使用して分散トレースを実装します。 ワークロードやインフラストラクチャ コンポーネントのログとメトリックには Azure Monitor Logs を使用します。 API から送信された要求の完全なエンドツーエンドのトレースを実装し、Event Hubs を通過してから、データベースに移動します。
重要
スタンプ監視リソースを別の監視リソース グループにデプロイします。 リソースにはスタンプとは異なるライフサイクルがあります。 詳細については、「スタンプ リソースのデータの監視」を参照してください。
アプリケーション監視の実装詳細
BackgroundProcessor コンポーネントでは、 Microsoft.ApplicationInsights.WorkerService NuGet パッケージを使用して、すぐに使用できるインストルメンテーションをアプリケーションから取得します。 Serilog は、アプリケーション内のすべてのログ記録にも使用されます。 Application Insights は、コンソール シンクに加えてシンクとして構成されます。 Application Insights 用 TelemetryClient インスタンスは、別のメトリックを追跡する必要があるときのみ直接使用されます。
実践的な要求追跡可能性を実証するため、各成功した API 要求と失敗した API 要求は、相関関係 ID ヘッダーを呼び出し元に返します。 アプリケーション サポート チームは、この ID を使用して Application Insights を検索し、前の図で示されている完全なトランザクションの詳細ビューを取得します。
注記
Application Insights SDK のアダプティブ サンプリングは既定で有効になっています。 アダプティブ サンプルは、すべての要求が、クラウドに送信され、ID で検索可能ではないことを意味します。 ミッション クリティカルなアプリケーション チームは、すべての要求を確実にトレースする必要があります。 運用環境では、アダプティブ サンプリングを無効にする必要があります。
Kubernetes 監視の実装の詳細
診断設定を使用して、AKS ログとメトリックを Azure Monitor Logs に送信できます。 AKS でコンテナー分析情報機能を使用することもできます。 Container Insights を有効にすると、Kubernetes デーモンセットを介して AKS クラスター内の各ノードに OMSAgentForLinux をデプロイできます。 OMSAgentForLinux は、Kubernetes クラスター内から多くのログとメトリックを収集することができ、それらを対応する Azure Monitor Logs ワークスペースに送信します。 これには、ポッド、デプロイ、サービス、およびクラスターの全体的な正常性に関するより詳細なデータが含まれます。
過度なログ記録はコストに悪影響を与え、メリットがありません。 このため、Container Insights 構成のワークロード ポッドでは、stdout ログ収集と Prometheus スクレイピングが無効になっています。これは、すべてのトレースが Application Insights を通じて既にキャプチャされており、重複レコードが生成されるからです。
アプリケーションの正常性の監視
アプリケーションの監視は、システムの問題をすばやく特定し、現在のアプリケーション状態について正常性モデルに通知するために使用されます。 "正常性エンドポイント" を通じて稼働状況の監視を行うことができます。 正常性プローブは、正常性監視データを使用して情報を提供します。 主要なロード バランサーは、その情報を使用して、異常なコンポーネントをすぐにローテーションから外します。
以下のレベルでヘルスモニタリングを行います。
AKS で実行されるワークロード ポッド。 これらのポッドにはヘルスプローブと稼働状態プローブがあり、AKS はポッドのライフサイクルを管理することができます。
ヘルスサービスは、クラスター上の専用コンポーネントです。 Azure Front Door は、各スタンプのヘルスチェックサービスをチェックし、正常でないスタンプを負荷分散から自動的に除外するように構成されています。
健康サービスの実装詳細
HealthService は、コンピューティング クラスター上の CatalogService や BackgroundProcessor などのその他コンポーネントと共に実行されているワークフロー コンポーネントです。
HealthService は、Azure Front Door の正常性チェックによって呼び出される REST API を提供し、スタンプの可用性を判断します。 基本的な liveness probe とは異なり、正常性サービスはより複雑なコンポーネントで、それ自体の状態に加えて依存関係の状態を提供します。
AKS クラスターがダウンしている場合、ヘルスサービスは応答せず、ワークロードを異常な状態にすることになります。 サービスが実行されている場合、ソリューションの重要コンポーネントに対して定期的なチェックを実行します。 すべてのチェックが 非同期的かつ並列に行われます。 いずれかのチェックが失敗した場合、スタンプ全体を使用できません。
警告
要求は複数の PoP 拠点から送信されるため、Azure Front Door ヘルスプローブは、ヘルスサービスに大きな負荷をかける場合があります。 ダウンストリーム コンポーネントのオーバーロードを防ぐために、効果的なキャッシュを実装します。
ヘルス サービスは、各スタンプの Application Insights リソースで明示的に構成された URL ピング テストにも使用されます。
HealthServiceの詳細については、「Application Health Service」を参照してください。