.NET に対して信頼性の高い Web アプリ パターンを適用する

Azure App Service
Azure Front Door
Azure Cache for Redis
.NET

この記事では、信頼性の高い Web アプリ パターンを適用する方法について説明します。 信頼性の高い Web アプリ パターンは、クラウドへの移行時に Web アプリを変更する方法 (再プラットフォーム) を定義する一連の原則と実装手法です。 クラウドで成功するために行う必要がある最小限のコード更新に焦点を当てています。

このガイダンスの適用を容易にするために、デプロイできる信頼性の高い Web アプリ パターンの参照実装があります。

参照実装のアーキテクチャを示す図。リファレンス実装のアーキテクチャ。このアーキテクチャの Visio ファイルをダウンロードします。

次のガイダンスでは、全体の例としてリファレンス実装を使用します。 信頼性の高い Web アプリ パターンを適用するには、適切に設計されたフレームワークの柱に沿った次の推奨事項に従います。

[信頼性]

信頼性により、顧客に確約したことをアプリケーションで確実に満たせるようにします。 詳細については、「信頼性の設計レビュー チェックリスト」を参照してください。 信頼性の高い Web アプリ パターンでは、信頼性を高めるためにコード レベルで 2 つの主要な設計パターン (再試行パターンとサーキット ブレーカー パターン) が導入されています。

再試行パターンを使用する

再試行パターンは、一時的なサービス中断 (一時的な障害と呼びます) に対処します。これは通常、数秒以内に解決されます。 これらの障害は多くの場合、クラウド環境でのサービス スロットリング、動的負荷分散、ネットワークの問題によって発生します。 再試行パターンを実装するには、失敗した要求を再送信し、構成可能な遅延と失敗前の試行を許可する必要があります。

再試行パターンを使用するアプリケーションでは、効率を高めるための Azure のクライアント ソフトウェア開発キット (SDK) とサービス固有の再試行メカニズムを統合する必要があります。 このパターンがないアプリケーションでは、次のガイダンスを使用して採用する必要があります。

最初に Azure サービスとクライアント SDK を試す

ほとんどの Azure サービスとクライアント SDK には、再試行メカニズムが組み込まれています。 実装を迅速化するには、Azure サービス用の組み込みの再試行メカニズムを使用する必要があります。

: リファレンス実装は、Entity Framework Core の 接続回復力を使用して、Azure SQL Database (次のコードを参照) 再試行パターンへのリクエストで再試行パターンを適用します。

services.AddDbContextPool<ConcertDataContext>(options => options.UseSqlServer(sqlDatabaseConnectionString,
    sqlServerOptionsAction: sqlOptions =>
    {
        sqlOptions.EnableRetryOnFailure(
        maxRetryCount: 5,
        maxRetryDelay: TimeSpan.FromSeconds(3),
        errorNumbersToAdd: null);
    }));

クライアント ライブラリで再試行がサポートされていない場合に Polly ライブラリを使用する

Azure サービスではない、または再試行パターンをネイティブにサポートしていない依存関係を呼び出す必要がある場合があります。 その場合は、Polly ライブラリを使用して再試行パターンを実装する必要があります。 Polly は、.NET の回復性と一時的な障害処理ライブラリです。 これを使用すると、fluent API を使用して、アプリケーションの一元的な場所での動作を記述できます。

例: リファレンス実装は、Pollly を使用して、ASP.NET Core の依存関係の挿入を設定します。 Polly では、IConcertSearchService オブジェクトを呼び出すオブジェクトがコードで構築されるたびに再試行パターンが適用されます。 Polly フレームワークでは、その動作は "ポリシー" と呼ばれます。 このコードは、GetRetryPolicy メソッドのポリシーを抽出し、フロントエンドの Web アプリによって Web API コンサート検索デバイス (次のコードを参照) を呼び出すたびに、GetRetryPolicy メソッドは再試行パターンを適用します。

private void AddConcertSearchService(IServiceCollection services)
{
    var baseUri = Configuration["App:RelecloudApi:BaseUri"];
    if (string.IsNullOrWhiteSpace(baseUri))
    {
        services.AddScoped<IConcertSearchService, MockConcertSearchService>();
    }
    else
    {
        services.AddHttpClient<IConcertSearchService, RelecloudApiConcertSearchService>(httpClient =>
        {
            httpClient.BaseAddress = new Uri(baseUri);
            httpClient.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
            httpClient.DefaultRequestHeaders.Add(HeaderNames.UserAgent, "Relecloud.Web");
        })
        .AddPolicyHandler(GetRetryPolicy())
        .AddPolicyHandler(GetCircuitBreakerPolicy());
    }
}

private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
    var delay = Backoff.DecorrelatedJitterBackoffV2(TimeSpan.FromMilliseconds(500), retryCount: 3);
    return HttpPolicyExtensions
      .HandleTransientHttpError()
      .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
      .WaitAndRetryAsync(delay);
}

RelecloudApiConcertSearchService インスタンスのポリシー ハンドラーでは、API に対するすべての要求に再試行パターンが適用されます。 HandleTransientHttpError ロジックを使用して、安全に再試行できる HTTP 要求を検出し、構成に基づいて要求を再試行します。 これには、エラーが発生した場合に API へのトラフィックで発生する可能性のあるバーストを滑らかにするためのランダム性が含まれています。

サーキット ブレーカー パターンを使用する

再試行パターンとサーキット ブレーカー パターンをペアリングすると、一時的な障害に関連しないサービスの中断を処理するアプリケーションの機能が拡張されます。 サーキット ブレーカー パターンは、アプリケーションが応答しないサービスに継続的にアクセスすることを防ぎます。 サーキット ブレーカー パターンでは、アプリケーションが解放され、CPU サイクルの無駄を回避するため、アプリケーションはエンド ユーザーに対するパフォーマンスの整合性を維持します。

: リファレンス実装は、GetCircuitBreakerPolicy メソッドにサーキット ブレーカー パターンを追加します (次のコードを参照)。

private static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
        .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30));
}

このコードでは、RelecloudApiConcertSearchService インスタンスのポリシー ハンドラーは、API に対するすべての要求にサーキット ブレーカー パターンを適用します。 ここでは HandleTransientHttpError ロジックを使用して、安全に再試行できる HTTP 要求を検出しますが、指定された期間の集計エラーの数を制限します。

セキュリティ

セキュリティは、重要なデータやシステムの意図的な攻撃や悪用に対する保証を提供します。 詳細については、「セキュリティの設計レビュー チェックリスト」を参照してください。 信頼性の高い Web アプリ パターンでは、マネージド ID を使用して ID 中心のセキュリティを実装します。 プライベート エンドポイント、Web アプリケーション ファイアウォール、および Web アプリへの制限付きアクセスにより、セキュリティで保護されたイングレスが提供されます。

最小限の特権を適用する

セキュリティと効率を確保するには、ユーザー (ユーザー ID) と Azure サービス (ワークロード ID) にのみ必要なアクセス許可を付与します。

ユーザー ID にアクセス許可を割り当てる

アプリケーションのニーズを評価して、重複のないすべてのユーザー アクションに対応するロール一式を定義します。 各ユーザーを最も適切なロールにマップします。 職務に必要なものにのみアクセスできることを確認します。

ワークロード ID にアクセス許可を割り当てる

データベースでの CRUD アクションやシークレットへのアクセスなど、操作に不可欠なアクセス許可のみを付与します。 ワークロード ID のアクセス許可は永続的であるため、ワークロード ID にジャスト・イン・タイムまたは短期のアクセス許可を提供することはできません。

  • ロールベースのアクセス制御 (RBAC) を使用します。 アクセス許可を割り当てるには、常に Azure RBAC から始めます。 それは正確な制御を提供し、アクセスが監査可能であり、粒度の細かいことを保証します。 Azure RBAC を使用して、サービスが目的の機能を実行するために必要なアクセス許可のみを付与します。

  • Azure サービス レベルのアクセス制御を補足します。 Azure RBAC が特定のシナリオに対応していない場合は、Azure サービス レベルのアクセス ポリシーを追加します。

認証と承認を構成する

認証と承認は、Web アプリケーションのセキュリティの重要な一部です。 認証は、ユーザーの ID を検証するプロセスです。 承認では、ユーザーがアプリケーション内で実行できるアクションを指定します。 目標は、セキュリティ体制を弱めることなく、認証と承認を実装することです。 この目標を達成するには、Azure アプリケーション プラットフォーム (Azure App Service) と ID プロバイダー (Microsoft Entra ID) の機能を利用する必要があります。

ユーザー認証を構成する

プラットフォームの機能を使用してユーザー認証を有効にして、Web アプリをセキュリティで保護します。 Azure App Service では、Microsoft Entra ID などの ID プロバイダーによる認証がサポートされ、コードから認証ワークロードがオフロードされます。

サービスの認証と承認を構成する

サービスの認証と承認を構成して、環境内のサービスに必要な機能を実行する権限を付与します。 Microsoft Entra ID のマネージド ID を使用して、サービス ID の作成と管理を自動化し、手動による資格情報管理を排除します。 マネージド ID を使用すると、Web アプリは Azure Key Vault やデータベースなどの Azure サービスに安全にアクセスできます。 また、Azure App Service へのデプロイの CI/CD パイプライン統合も容易になります。 ただし、ハイブリッド展開やレガシー システムなどのシナリオでは、引き続きオンプレミス認証ソリューションを使用して移行を簡略化します。 システムで最新の ID 管理アプローチの準備ができたら、マネージド ID に移行します。 詳細については、「マネージド ID の監視」を参照してください。

DefaultAzureCredential を使用してコードを設定する

DefaultAzureCredential を使用して、クラウドのローカル開発とマネージド IDの資格情報を指定します。 DefaultAzureCredential は、OAuth トークンの取得に対して TokenCredential を生成します。 ほとんどの Azure SDK シナリオと Microsoft クライアント ライブラリを処理します。 アプリケーションの環境で正しい ID を使用することが検出され、必要に応じてアクセス トークンが要求されます。 DefaultAzureCredential は、Azure にデプロイされたアプリケーションの認証を効率化します。詳細については、「DefaultAzureCredential」を参照してください。

例: リファレンス実装は、スタートアップ中に DefaultAzureCredential クラスを使用して、Web API と Key Vault 間でマネージド ID を使用できるようにします (次のコードを参照)。

builder.Configuration.AddAzureAppConfiguration(options =>
{
     options
        .Connect(new Uri(builder.Configuration["Api:AppConfig:Uri"]), new DefaultAzureCredential())
        .ConfigureKeyVault(kv =>
        {
            // Some of the values coming from Azure App Configuration are stored Key Vault. Use
            // the managed identity of this host for the authentication.
            kv.SetCredential(new DefaultAzureCredential());
        });
});

Infrastructure as Code を使用してマネージド ID を作成する

マネージド ID をサポートするように Azure インフラストラクチャを作成および構成するには、Bicep テンプレートを使用する必要があります。 マネージド ID ではシークレットやパスワードを使用しないため、整合性を確保するために Key Vault やシークレットのローテーション戦略は必要ありません。 接続文字列は、App Configuration サービスに格納できます。

例: リファレンス実装では、Bicep テンプレートを使用して、(1) マネージド ID を作成し、(2) ID を Web アプリに関連付け、(3) SQL データベースにアクセスするためのアクセス許可を ID に付与します。 接続文字列の Authentication 引数は、Microsoft クライアント ライブラリにマネージド ID に接続するように指示します (次のコードを参照)。

    Server=tcp:my-sql-server.database.windows.net,1433;Initial Catalog=my-sql-database;Authentication=Active Directory Default

詳細については、.NET App Service から SQL Database への接続に関する記事を参照してください。

中央シークレット ストアを使用してシークレットを管理する

アプリケーションをクラウドに移動するときは、Azure Key Vault を使用して、そのようなすべてのシークレットを安全に格納します。 この一元化されたリポジトリでは、セキュリティで保護されたストレージ、キー ローテーション、アクセス監査、およびマネージド ID をサポートしていないサービスの監視が提供されます。 アプリケーション構成の場合は、「Azure App Configuration」が推奨されます。

例: 参照実装では、(1) PostgreSQL データベースのユーザー名とパスワード、(2) Redis Cache パスワード、(3) Microsoft Authentication Library (MSAL) 実装に関連付けられている Microsoft Entra ID のクライアント シークレットが Key Vault に格納されます。

Key Vault を HTTP 要求フローに入れない

各 HTTP 要求中ではなく、アプリケーションの起動時に Key Vault からシークレットを読み込みます。 Key Vault は、デプロイ時に機密データを安全に格納および取得することを目的としています。 HTTP 要求内の高頻度アクセスは、Key Vault のスループット機能を超える可能性があり、要求の制限と HTTP 状態コード 429 エラーが発生する可能性があります。 詳細については、Key Vault のトランザクション制限に関する記事を参照してください。

Key Vault のシークレットのアクセスに 1 つのメソッドを使用する

Key Vault のシークレットにアクセスするように Web アプリを構成する場合、主に次の 2 つのオプションがあります。

  • App Service App 設定: App Service のアプリ設定を使用して、環境変数としてシークレットを直接挿入します。

  • 直接シークレット参照: アプリケーション コード内でシークレットを直接参照します。 アプリケーションが Key Vault と通信できるように、application.properties 向け Java アプリケーションなどの特定のリファレンスをアプリケーションのプロパティ ファイルに追加します。

これらのメソッドの 1 つを選択し、簡潔にし、不要な複雑さを避けるためにそのメソッドを使用することが重要です。

一時的なアクセス方法を優先する

一時的なアクセス許可を使用して、不正アクセスや侵害から保護します。 一時的なアクセスには Shared Access Signature (SAS) を使用します。 ユーザー委任 SAS を使用して、一時的なアクセスを許可するときにセキュリティを最大化します。 Microsoft Entra ID の資格情報を使用し、ストレージ アカウント キーを必要としない唯一の SAS です。

プライベート エンドポイントを使用する

サポートされているすべての Azure サービスについて、すべての運用環境でプライベート エンドポイントを使用します。 プライベート エンドポイントは、Azure 仮想ネットワーク内のリソースと Azure サービス間のプライベート接続を提供します。 既定では、ほとんどの Azure サービスへの通信はパブリック インターネットを通過します。 プライベート エンドポイントには、コードの変更、アプリの構成、接続文字列が必要ありません。 詳細については、プライベート エンドポイントを作成する方法およびエンドポイント セキュリティのベスト プラクティスに関する記事を参照してください。

例: zure App Configuration、Azure SQL Database、Azure Cache for Redis、Azure Storage、Azure App Service、および Key Vault はプライベート エンドポイントを使用します。

Web アプリケーション ファイアウォールを使用して受信インターネット トラフィックを制限する

Web アプリへの受信インターネット トラフィックはすべて、Web アプリケーション ファイアウォールを通過して、一般的な Web 攻撃から保護する必要があります。 パブリック ロード バランサーがある場合は、すべての受信インターネット トラフィックを強制的に通過させ、Web アプリケーション ファイアウォールを通過させます。

例: リファレンス実装では、Front Door と Azure Web Application Firewall を介して、すべての受信インターネット トラフィックが強制的に送信されます。 運用環境では、元の HTTP ホスト名を保持します

データベース セキュリティを構成

データベースに対する管理者レベルのアクセス権には、特権操作を実行するためのアクセス許可が付与されています。 特権操作には、データベースの作成と削除、テーブル スキーマの変更、ユーザーのアクセス許可の変更などがあります。 開発者は、多くの場合、データベースを維持したり、問題のトラブルシューティングを行ったりするために、管理者レベルのアクセス権を必要としています。

  • 永続的で高度なアクセス許可は避けます。 開発者には Just-In-Time アクセス権のみを付与して特権操作を実行してもらう必要があります。 Just-In-Time アクセス権を使用するには、ユーザーは、一時的なアクセス許可を取得してから、権限が必要な操作を実行します。

  • アプリケーションには高度なアクセス許可を付与しません。 アプリケーション ID に管理者レベルのアクセス権を付与しないでください。 アプリケーションはデータベースに最小特権でアクセスするよう構成する必要があります。 バグとセキュリティ侵害の影響範囲を限定します。

コストの最適化

コストの最適化とは、不要な費用と管理オーバーヘッドを削減する方法を検討することです。 詳細については、「コスト最適化の設計レビュー チェックリスト」を参照してください。 信頼性の高い Web アプリ パターンでは、よりコスト最適化された Web アプリを実現するために、適正規模の手法、オートスケール、効率的なリソース使用が実装されています。

各環境のリソースを合理化する

Azure サービスのさまざまなパフォーマンス レベルを理解し、各環境のニーズに適した SKU のみを使用します。 運用環境には、運用に必要なサービス レベル アグリーメント (SLA)、機能、スケールを満たす SKU が必要です。 ただし、非運用環境では通常は同じ機能は必要ありません。 さらに節約するには、Azure Dev/Test の価格オプションAzure の予約コンピューティングの Azure 節約プランを検討します。

例: リファレンス実装は、Bicep パラメーターを使用して、リソース デプロイ構成をトリガーします。 これらのパラメーターの 1 つは、デプロイするリソース層 (SKU) を示します。 Web アプリは、パフォーマンスが高く、高額な SKU を本番環境に使用し、安い SKU を非本番環境に使用します (次のコードを参照)。

var redisCacheSkuName = isProd ? 'Standard' : 'Basic'
var redisCacheFamilyName = isProd ? 'C' : 'C'
var redisCacheCapacity = isProd ? 1 : 0

自動スケールの使用

オートスケールを使用して、運用環境の水平スケーリングを自動化する必要があります。 パフォーマンス メトリックに基づく自動スケーリング。 アプリケーションのスケーリング条件がよくわからない場合、CPU 使用率のパフォーマンス トリガーが出発点として適しています。 Web アプリケーションの動作に対応するように、スケーリング トリガー (CPU、RAM、ネットワーク、ディスク) を構成して調整する必要があります。 需要の頻繁な変化に合わせて垂直方向にスケーリングしないでください。 コスト効率が低くなります。 詳細については、「Azure App Service でのスケーリング」および「Microsoft Azure での自動スケーリング」を参照してください。

例: リファレンス実装は、Bicep テンプレートで次の構成を使用します。 これによって Azure App Service の自動スケーリング ルールが作成されます。 このルールでは、最大 10 個のインスタンスにスケールアップし、既定値は 1 つのインスタンスになります。 スケール インとスケールアウトのトリガーとして CPU 使用率を使用します。Web アプリのホスティング プラットフォームは、85% の CPU 使用率でスケールアウトし、60% でスケールインします。 スケールアウト設定を、100% に近い割合とせずに 85% とすることで、スティッキー セッションによって引き起こされる蓄積されたユーザー トラフィックから保護するためのバッファーが提供されます。 また、最大の CPU 使用率を回避するために早期にスケーリングすることで、大量のバースト トラフィックから保護します。 これらの自動スケール ルールは汎用ではありません (次のコードを参照)。

resource autoScaleRule 'Microsoft.Insights/autoscalesettings@2022-10-01' = if (autoScaleSettings != null) { 
  name: '${name}-autoscale' 
  location: location 
  tags: tags 
  properties: { 
    targetResourceUri: appServicePlan.id 
    enabled: true 
    profiles: [ 
      { 
        name: 'Auto created scale condition' 
        capacity: { 
          minimum: string(zoneRedundant ? 3 : autoScaleSettings!.minCapacity) 
          maximum: string(autoScaleSettings!.maxCapacity) 
          default: string(zoneRedundant ? 3 : autoScaleSettings!.minCapacity) 
        } 
        rules: [ 
          ... 
        ] 
      } 
    ] 
  } 
}

リソースを効率的に使用する

  • 共有サービスを使用します。 特定のリソースを一元化して共有すると、コストの最適化と管理オーバーヘッドの削減が実現します。 共有ネットワーク リソースをハブ仮想ネットワークに配置します。

    例: リファレンス実装では、Azure Firewall、Azure Bastion、Key Vault がハブ仮想ネットワークに配置されます。

  • 未使用の環境を削除します。 コストを最適化するには、時間外や休暇中に非運用環境を削除します。 Infrastructure as Code を使用すると、Azure リソースと環境全体を削除できます。 Bicep テンプレートから削除するリソースの宣言を削除します。 What-If 操作を使用して、変更を有効にする前にプレビューします。 後で必要なデータをバックアップします。 削除するリソースへの依存関係について理解します。 依存関係がある場合は、それらのリソースも更新または削除する必要があります。 詳細については、「Bicep デプロイの What-If 操作」を参照してください。

  • 機能を併置します。 空き容量がある場合は、アプリケーション リソースと機能を 1 つの Azure リソースに併置します。 たとえば、複数の Web アプリで 1 つのサーバー (App Service プラン) を使用したり、1 つのキャッシュで複数のデータ型をサポートしたりできます。

    例: リファレンス実装では、フロントエンド (カートと MSAL トークンの格納) とバックエンド (近日のコンサート データを保持) Web アプリの両方でセッション管理を行う単一の Azure Cache for Redis インスタンスを使用します。 これは最小の Redis SKU を選択し、必要以上の容量を提供し、複数のデータ型を使用してコストを制御することで効率的に利用します。

オペレーショナル エクセレンス

オペレーショナル エクセレンスは、アプリケーションをデプロイし、それを運用環境で実行し続ける運用プロセスをカバーします。 詳細については、「オペレーショナル エクセレンスのデザイン レビュー チェック一覧」を参照してください。 信頼性の高い Web アプリ パターンは、インフラストラクチャのデプロイと監視用に Infrastructure as Code を実装します。

デプロイの自動化

CI/CD パイプラインを使用して、ソース制御から本番環境に変更をデプロイします。 Azure DevOps を使用している場合は、Azure Pipelines を使用する必要があります。 GitHub を使用している場合は、GitHub Actions を使用します。 Azure supports ARM テンプレート (JSON)、Bicep、Terraform には、各 Azure リソース用のテンプレートがあります。詳細については、「Bicep、Azure Resource Manager および Terraform」 テンプレートおよび「反復可能なインフラストラクチャ」を参照してください。

例: リファレンス実装は、Azure Dev CLI と Infrastructure as Code (Bicep テンプレート) を使用して、Azure リソースの作成、構成の設定、必要なリソースのデプロイを行います。

監視の構成

Web アプリを監視するには、アプリケーション コード、インフラストラクチャ (ランタイム)、プラットフォーム (Azure リソース) からメトリックとログを収集して分析します。 アーキテクチャに各 Azure リソースの診断設定を追加します。 Azure サービスごとに、取得できるログとメトリックのセットは異なります。 詳細については、「プラットフォームの監視」および「App Service の監視」を参照してください。

ベースライン メトリックを監視する

Azure Application Insights を使用して、要求スループット、平均要求期間、エラー、依存関係の監視などのベースライン メトリックを追跡します。 NuGet パッケージ Microsoft.ApplicationInsights.AspNetCoreAddApplicationInsightsTelemetry を使用して、テレメトリ収集を有効にします。 詳細については、「Application Insights テレメトリ」「.NET での依存関係の挿入を有効にする」を参照してください 。

例: リファレンス実装はコードを使用して、Application Insights のベースライン メトリックを構成します (次のコードを参照)。

public void ConfigureServices(IServiceCollection services)
{
   ...
   services.AddApplicationInsightsTelemetry(Configuration["App:Api:ApplicationInsights:ConnectionString"]);
   ...
}

必要に応じてカスタム テレメトリを作成する

Application Insights を使用してカスタム テレメトリを収集し、Web アプリ ユーザーをより深く理解します。 TelemetryClient クラスのインスタンスを作成し、TelemetryClient メソッドを使用して、適切なメトリックを作成します。 クエリを Azure ダッシュボード ウィジェットに変換します。

例: リファレンス実装は、Web アプリがトランザクションを正常に完了していることを運用チームが確認するのに役立つメトリックを追加します。 これにより、要求数や CPU 使用率を測定することによってではなく、顧客が注文できるかどうかを監視することで、Web アプリがオンラインであることが検証されます。 参照実装では、依存関係の挿入による TelemetryClientTrackEvent メソッドを使用して、カートの利用状況に関するイベントのテレメトリを収集します。 テレメトリは、ユーザーが追加、削除、購入したチケットを追跡します (次のコードを参照)。

  • AddToCart は、ユーザーがカートに特定のチケット (ConcertID) を追加した回数をカウントします。
  • RemoveFromCart は、ユーザーがカートから削除したチケットを記録します。
  • CheckoutCart は、ユーザーがチケットを購入するたびにイベントを記録します。

this.telemetryClient.TrackEvent は、カートに追加されたチケットをカウントします。 ここではイベント名 (AddToCart) が指定され、concertIdcount を持つディクショナリが指定されます (次のコードを参照)。

this.telemetryClient.TrackEvent("AddToCart", new Dictionary<string, string> {
    { "ConcertId", concertId.ToString() },
    { "Count", count.ToString() }
});

詳細については、以下を参照してください:

ログ ベースのメトリックを収集する

重要なアプリケーションの正常性とメトリックをより詳細に把握するには、ログ ベースのメトリックを追跡します。 Application Insights で Kusto 照会言語 (KQL) クエリを使用して、データを検索および整理できます。 詳細については、「Application Insights ログベースのメトリック」および「Application Insights のログベースのメトリックと事前に集計されたメトリック」を参照してください。

プラットフォーム診断を有効にする

Azure の診断設定では、収集するプラットフォーム ログとメトリックと、それらを保存する場所を指定できます。 プラットフォーム ログは、診断情報と監査情報を提供する組み込みのログです。 プラットフォーム診断はほとんどの Azure サービスで有効にできますが、各サービスでは独自のログ カテゴリが定義されています。 各種 Azure サービスにはログのカテゴリがあって、そこから選べます。

  • サポートされているすべてのサービスの診断を有効にします。 Azure サービスはプラットフォーム ログを自動的に作成しますが、サービスが自動的に保存することはありません。 それには各サービスの診断設定を有効にする必要があります。また、診断をサポートするすべての Azure サービスで有効にしてください。

  • アプリケーション ログと同じ送信先に診断を送信します。 診断を有効にしたら、収集するログと、ログの送信先を選びます。 プラットフォーム ログはアプリケーション ログと同じ宛先に送信して、2 つのデータセットを関連付けることができるようにする必要があります。

パフォーマンス効率

パフォーマンス効率とは、ユーザーからの要求に合わせて効率的な方法でワークロードをスケーリングできることです。 詳細については、「パフォーマンス効率の設計レビュー チェックリスト」を参照してください。 信頼性の高い Web アプリ パターンでは、キャッシュ アサイド パターンを使用して、要求の多いデータの待機時間を最小限に抑えます。

キャッシュ アサイド パターンを使用する

キャッシュ アサイド パターンは、メモリ内データ管理を向上させるキャッシュ戦略です。 このパターンにより、データ要求を処理し、キャッシュと永続的ストレージ (データベースなど) の間の整合性を確保する責任がアプリケーションに割り当てられます。 Web アプリは、データ要求を受信すると、最初にキャッシュを検索します。 データが見つからない場合は、データベースからデータを取得し、要求に応答し、それに応じてキャッシュを更新します。 この方法では、応答時間が短縮され、スループットが向上し、スケーリングの必要性が軽減されます。 また、プライマリ データストアの負荷を軽減し、停止リスクを最小限に抑えることで、サービスの可用性を強化します。

例: リファレンス実装では、チケット販売に不可欠な今後のコンサートの情報など、重要なデータをキャッシュすることで、アプリケーションの効率が向上します。 ASP.NET Core の分散メモリ キャッシュをメモリ内項目ストレージに使用します。 アプリケーションでは、特定の接続文字列が見つかると、Azure Cache for Redis が自動的に使用されます。 また、Redis を使用せずにローカル開発環境をサポートし、セットアップを簡素化し、コストと複雑さを軽減します。 メソッド (AddAzureCacheForRedis) は、Azure Cache for Redis を使用するようにアプリケーションを構成します (次のコードを参照)。

private void AddAzureCacheForRedis(IServiceCollection services)
{
    if (!string.IsNullOrWhiteSpace(Configuration["App:RedisCache:ConnectionString"]))
    {
        services.AddStackExchangeRedisCache(options =>
        {
            options.Configuration = Configuration["App:RedisCache:ConnectionString"];
        });
    }
    else
    {
        services.AddDistributedMemoryCache();
    }
}

詳細については、「ASP.NET Core の分散キャッシュ」および「AddDistributedMemoryCache メソッド」を参照してください。

必要性の高いデータをキャッシュする

最も頻繁にアクセスされるデータのキャッシュに優先順位を付けます。 ユーザー エンゲージメントとシステム パフォーマンスを促進する主要なデータ ポイントを特定します。 キャッシュアサイド パターンの有効性を最適化し、待機時間とデータベースの負荷を大幅に削減するために、これらの領域専用のキャッシュ戦略を実装します。 Azure Monitor を使用して、データベースの CPU、メモリ、ストレージを追跡します。 これらのメトリックは、より小さなデータベース SKU を使用できるかどうかを判断するのに役立ちます。

例:リファレンス実装では、今後のコンサートをサポートするデータがキャッシュされます。 [Upcoming Concerts] (今後のコンサート) ページでは、SQL Database へのほとんどのクエリが作成され、訪問ごとに一貫した出力が生成されます。 キャッシュ アサイド パターンでは、データベースの負荷を軽減するために、このページの最初の要求の後にデータがキャッシュされます。 次のコードでは、GetUpcomingConcertsAsync メソッドを使用して、SQL Database から Redis キャッシュにデータをプルします。 このメソッドでは最新のコンサートをキャッシュに設定します。 このメソッドでは、時間でフィルター処理し、データを並べ替え、データをコントローラーに返して結果を表示します (次のコードを参照)。

public async Task<ICollection<Concert>> GetUpcomingConcertsAsync(int count)
{
    IList<Concert>? concerts;
    var concertsJson = await this.cache.GetStringAsync(CacheKeys.UpcomingConcerts);
    if (concertsJson != null)
    {
        // There is cached data. Deserialize the JSON data.
        concerts = JsonSerializer.Deserialize<IList<Concert>>(concertsJson);
    }
    else
    {
        // There's nothing in the cache. Retrieve data from the repository and cache it for one hour.
        concerts = await this.database.Concerts.AsNoTracking()
            .Where(c => c.StartTime > DateTimeOffset.UtcNow && c.IsVisible)
            .OrderBy(c => c.StartTime)
            .Take(count)
            .ToListAsync();
        concertsJson = JsonSerializer.Serialize(concerts);
        var cacheOptions = new DistributedCacheEntryOptions {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
        };
        await this.cache.SetStringAsync(CacheKeys.UpcomingConcerts, concertsJson, cacheOptions);
    }
    return concerts ?? new List<Concert>();
}

キャッシュ データを最新の状態に保つ

最新のデータベース変更と同期するように、定期的なキャッシュ更新をスケジュールします。 データ ボラティリティとユーザーのニーズに基づいて最適なリフレッシュ レートを決定します。 この方法により、アプリケーションはキャッシュ アサイド パターンを使用して、迅速なアクセスと最新の情報の両方を提供できます。

例:リファレンス実装では、1 時間のデータのみキャッシュされます。 これには、データが変更されたときにキャッシュ キーをクリアするプロセスがあります。 CreateConcertAsync メソッドは、キャッシュ キーがクリアされます (次のコードを参照)。

public async Task<CreateResult> CreateConcertAsync(Concert newConcert)
{
    database.Add(newConcert);
    await this.database.SaveChangesAsync();
    this.cache.Remove(CacheKeys.UpcomingConcerts);
    return CreateResult.SuccessResult(newConcert.Id);
}

データの一貫性を確保する

データベース書き込み操作の直後にキャッシュを更新するメカニズムを実装します。 イベント駆動の更新または専用のデータ管理クラスを使用して、キャッシュの一貫性を確保します。 キャッシュとデータベースの変更を一貫して同期することは、キャッシュ アサイド パターンの主要な部分です。

例: リファレンス実装では、UpdateConcertAsync メソッドを使用して、キャッシュ内のデータの整合性を維持します (次のコードを参照)。

public async Task<UpdateResult> UpdateConcertAsync(Concert existingConcert), 
{
   database.Update(existingConcert);
   await database.SaveChangesAsync();
   this.cache.Remove(CacheKeys.UpcomingConcerts);
   return UpdateResult.SuccessResult();
}

データベース パフォーマンスをテストする

データベースのパフォーマンスは、アプリケーションのパフォーマンスとスケーラビリティに影響を与える可能性があります。 データベースのパフォーマンスをテストして、最適化されていることを確認することが重要です。 重要な考慮事項としては、適切なクラウド リージョンの選択、接続プール、キャッシュアサイド パターン、クエリの最適化などがあります。

  • ネットワーク ホップをテストします。 アプリケーションをクラウドに移動すると、ネットワーク ホップが追加されてデータベースに待機時間が発生する可能性があります。 新しいクラウド環境で導入される追加のホップをテストする必要があります。

  • パフォーマンス ベースラインを確立します。 初期ベースラインとしてオンプレミスのパフォーマンス メトリックを使用して、クラウドのアプリケーション パフォーマンスと比較する必要があります。

次のステップ

GitHub リポジトリの手順に従って、参照実装をデプロイします。 .NET アプリケーション、Web アプリ、クラウドのベスト プラクティス、移行の詳細については、次のリソースを参照してください。

.NET Framework アプリケーションのアップグレード

参照実装は、Windows を実行する App Service にデプロイされますが、Linux 上で実行できます。 App Service Windows プラットフォームを使用すると、新しいフレームワーク バージョンにアップグレードすることなく、.NET Framework Web アプリを Azure に移動できます。 Linux App Service プラン、または最新バージョンの .NET に追加された新機能とパフォーマンスの向上については、次のガイダンスを参照してください。

Azure での Web アプリの概要

Azure 上の .NET Web アプリケーションへの実践的な手引きについては、こちらの基本的な .NET Web アプリケーションのデプロイに関するガイダンスを参照してください。

クラウドのベスト プラクティス

Azure の導入とアーキテクチャのガイダンスについては、次を参照してください。

信頼性の高い Web アプリよりも高い SLO が必要なアプリケーションについては、「ミッションクリティカルなワークロード」を参照してください。

移行ガイダンス

次のツールとリソースは、オンプレミスのリソースを Azure に移行するのに役立ちます。