Web 開発のベスト プラクティス (Azure を使用したReal-World Cloud Apps の構築)

作成者 : Rick AndersonTom Dykstra

Fix It プロジェクトのダウンロード または 電子書籍のダウンロード

Azure 電子書籍 を使用した Real World Cloud Apps の構築 は、Scott Guthrie が開発したプレゼンテーションに基づいています。 クラウド向けの Web アプリの開発を成功させるために役立つ 13 のパターンとプラクティスについて説明します。 電子書籍の詳細については、 最初の章を参照してください。

最初の 3 つのパターンは、アジャイル開発プロセスを設定することでした。残りはアーキテクチャとコードについてです。 これは、Web 開発のベスト プラクティスのコレクションです。

これらのプラクティスは、クラウド アプリだけでなく、すべての Web 開発に有効ですが、クラウド アプリでは特に重要です。 これらは連携して、クラウド環境によって提供される非常に柔軟なスケーリングを最適に使用するのに役立ちます。 これらのプラクティスに従わない場合は、アプリケーションをスケーリングしようとしたときに制限が発生します。

スマート ロード バランサーの背後にあるステートレス Web 層

ステートレス Web 層 は、アプリケーション データを Web サーバーのメモリまたはファイル システムに格納しないことを意味します。 Web 層をステートレスに保つことで、より優れたカスタマー エクスペリエンスを提供し、コストを節約できます。

  • Web 層がステートレスで、ロード バランサーの背後にある場合は、サーバーを動的に追加または削除することで、アプリケーション トラフィックの変化に迅速に対応できます。 実際に使用している限り、サーバー リソースに対してのみ料金を支払うクラウド環境では、需要の変化に対応する能力が大幅に節約される可能性があります。
  • ステートレス Web 層は、アーキテクチャ上、アプリケーションをスケールアウトする方がはるかに簡単です。 これにより、スケーリングのニーズに迅速に対応し、プロセスの開発とテストにかかるコストを削減できます。
  • オンプレミス サーバーなどのクラウド サーバーは、修正プログラムを適用して再起動する必要があります。Web 層がステートレスの場合、サーバーが一時的にダウンしたときにトラフィックを再ルーティングしても、エラーや予期しない動作は発生しません。

ほとんどの実際のアプリケーションでは、Web セッションの状態を格納する必要があります。ここでのメインポイントは、それを Web サーバーに格納することです。 キャッシュ プロバイダーを使用して、クライアント上の cookie やプロセス外のサーバー側 ASP.NET セッション状態など、他の方法で状態を格納できます。 ローカル ファイル システムではなく 、Windows Azure Blob Storage にファイルを格納できます。

Web 層がステートレスな場合に Windows Azure Web サイトでアプリケーションをスケーリングする方法の例として、管理ポータルの Windows Azure Web サイトの [ スケール ] タブを参照してください。

[スケール] タブ

Web サーバーを追加する場合は、インスタンス数スライダーを右にドラッグするだけです。 これを 5 に設定して [ 保存] をクリックすると、数秒以内に Windows Azure に 5 台の Web サーバーが Web サイトのトラフィックを処理します。

5 つのインスタンス

インスタンス数を 3 に設定するか、1 に戻すのと同じように簡単に設定できます。 スケール バックすると、Windows Azure は時間単位ではなく分単位で課金されるため、すぐに節約を開始します。

また、CPU 使用率に基づいて Web サーバーの数を自動的に増減するように Windows Azure に指示することもできます。 次の例では、CPU 使用率が 60% を下回ると、Web サーバーの数は少なくとも 2 に減少し、CPU 使用率が 80% を超えると、Web サーバーの数は最大 4 まで増加します。

CPU 使用率によるスケーリング

または、サイトが勤務時間中にのみビジー状態になることがわかっている場合はどうでしょうか。 日中に複数のサーバーを実行し、1 つのサーバーの夜、夜間、週末に減らすよう Windows Azure に指示できます。 次の一連のスクリーン ショットは、午前 8 時から午後 5 時までの勤務時間中に 1 台のサーバーを稼働するように Web サイトを設定する方法を示しています。

スケジュールによるスケーリング

スケジュール時刻を設定する

昼間のスケジュール

平日のスケジュール

週末のスケジュール

もちろん、このすべては、スクリプトとポータルで行うことができます。

Windows Azure では、Web 層をステートレスに保つことで、サーバー VM を動的に追加または削除する障害を回避できる限り、アプリケーションのスケールアウト機能はほぼ無制限です。

セッション状態を回避する

ユーザー セッションの状態をなんらかの形で格納しないのは、実際のクラウド アプリケーションでは実用的でない場合が多いですが、方法によっては、パフォーマンスとスケーラビリティに与える影響が大きくなります。 状態を格納する必要がある場合は、状態の量を少なくし、Cookie に格納することをお勧めします。 これが実現できない場合、次に最適な解決策は 、分散メモリ内キャッシュのプロバイダー ASP.NET セッション状態を使用することです。 パフォーマンスとスケーラビリティの観点から最もお勧めできないのが、データベースを利用したセッション状態プロバイダーを使用する方法です。

CDN を使用して静的ファイル資産をキャッシュする

CDN は、コンテンツ配信ネットワークの頭字語です。 イメージやスクリプト ファイルなどの静的ファイル資産を CDN プロバイダーに提供し、プロバイダーは世界中のデータ センターにこれらのファイルをキャッシュして、ユーザーがアプリケーションにアクセスするたびに、キャッシュされた資産に対して比較的迅速な応答と待機時間を短縮できるようにします。 これにより、サイトの全体的な読み込み時間が短縮され、Web サーバーの負荷が軽減されます。 CDN は、地理的に広く分散されている対象ユーザーに到達する場合に特に重要です。

Windows Azure には CDN があり、Windows Azure または任意の Web ホスティング環境で実行されるアプリケーションで他の CDN を使用できます。

.NET 4.5 の非同期サポートを使用して、呼び出しのブロックを回避する

.NET 4.5 では、タスクを非同期的に処理する方がはるかに簡単になるように、C# と VB のプログラミング言語が強化されました。 非同期プログラミングの利点は、複数の Web サービス呼び出しを同時に開始する場合など、並列処理の場合だけではありません。 また、高負荷条件下でより効率的かつ信頼性の高いパフォーマンスを実現できます。 Web サーバーには使用可能なスレッドの数が限られており、すべてのスレッドが使用されている場合の高負荷条件下では、受信要求はスレッドが解放されるまで待機する必要があります。 アプリケーション コードでデータベース クエリや Web サービス呼び出しなどのタスクが非同期的に処理されない場合、サーバーが I/O 応答を待機している間、多くのスレッドが不必要に関連付けられます。 これにより、負荷の高い条件下でサーバーが処理できるトラフィックの量が制限されます。 非同期プログラミングでは、Web サービスまたはデータベースがデータを返すのを待機しているスレッドは、 が受信されるデータまで、サービスの新しい要求まで解放されます。 ビジー状態の Web サーバーでは、数百または数千の要求を迅速に処理できます。そうしないと、スレッドが解放されるのを待機することになります。

前に説明したように、Web サイトを処理する Web サーバーの数を増やすのと同じくらい簡単です。 そのため、サーバーのスループットを向上できる場合は、それらの数を必要とせず、特定のトラフィック 量に対して必要なサーバーが他の方法よりも少ないため、コストを削減できます。

.NET 4.5 非同期プログラミング モデルのサポートは、Web Forms、MVC、Web API の ASP.NET 4.5、Entity Framework 6、および Windows Azure Storage API に含まれています。

ASP.NET 4.5 での非同期サポート

ASP.NET 4.5 では、非同期プログラミングのサポートが言語だけでなく、MVC、Web Forms、Web API フレームワークにも追加されました。 たとえば、ASP.NET MVC コントローラー アクション メソッドは、Web 要求からデータを受け取り、そのデータをビューに渡し、ブラウザーに送信する HTML を作成します。 多くの場合、アクション メソッドは、Web ページに表示したり、Web ページに入力されたデータを保存したりするために、データベースまたは Web サービスからデータを取得する必要があります。 これらのシナリオでは、アクション メソッドを非同期にするのは簡単です。ActionResult オブジェクトを返す代わりに、Task<ActionResult> を返し、非同期キーワード (keyword)でメソッドをマークします。 メソッド内では、待機時間を含む操作がコード行によって開始されると、await キーワード (keyword)でマークされます。

データベース クエリのリポジトリ メソッドを呼び出す単純なアクション メソッドを次に示します。

public ActionResult Index()
{
    string currentUser = User.Identity.Name;
    var result = fixItRepository.FindOpenTasksByOwner(currentUser);

    return View(result);
}

データベース呼び出しを非同期的に処理するのと同じメソッドを次に示します。

public async Task<ActionResult> Index()
{
    string currentUser = User.Identity.Name;
    var result = await fixItRepository.FindOpenTasksByOwnerAsync(currentUser);

    return View(result);
}

では、コンパイラによって適切な非同期コードが生成されます。 アプリケーションが の呼び出しを FindTaskByIdAsync行うと、ASP.NET は要求を FindTask 行い、ワーカー スレッドをアンワインドして、別の要求を処理できるようにします。 要求が FindTask 完了すると、スレッドが再起動され、その呼び出し後に発生するコードの処理が続行されます。 要求が開始されてからデータが返されるまでの FindTask 間の中間に、応答を待機している場合に関連付けられている便利な作業を実行できるスレッドがあります。

非同期コードにはオーバーヘッドがいくつかありますが、負荷の低い条件下ではオーバーヘッドは無視できますが、高負荷の条件下では、使用可能なスレッドを待機している要求を処理できます。

ASP.NET 1.1 以降、この種の非同期プログラミングを実行することは可能でしたが、書き込みが困難でエラーが発生しやすく、デバッグが困難でした。 ASP.NET 4.5 でコーディングを簡略化したので、それを行わない理由はもうありません。

Entity Framework 6 での非同期サポート

4.5 の非同期サポートの一環として、Web サービス呼び出し、ソケット、ファイル システム I/O の非同期サポートが提供されましたが、Web アプリケーションの最も一般的なパターンはデータベースにヒットすることです。また、データ ライブラリでは非同期がサポートされていませんでした。 Entity Framework 6 では、データベース アクセスの非同期サポートが追加されました。

Entity Framework 6 では、クエリまたはコマンドをデータベースに送信するすべてのメソッドに非同期バージョンがあります。 次の例は、 Find メソッドの非同期バージョンを示しています。

public async Task<FixItTask> FindTaskByIdAsync(int id)
{
    FixItTask fixItTask = null;
    Stopwatch timespan = Stopwatch.StartNew();

    try
    {
        fixItTask = await db.FixItTasks.FindAsync(id);
        
        timespan.Stop();
        log.TraceApi("SQL Database", "FixItTaskRepository.FindTaskByIdAsync", timespan.Elapsed, "id={0}", id);
    }
    catch(Exception e)
    {
        log.Error(e, "Error in FixItTaskRepository.FindTaskByIdAsynx(id={0})", id);
    }

    return fixItTask;
}

また、この非同期サポートは、挿入、削除、更新、簡単な検索だけでなく、LINQ クエリでも機能します。

public async Task<List<FixItTask>> FindOpenTasksByOwnerAsync(string userName)
{
    Stopwatch timespan = Stopwatch.StartNew();

    try
    {
        var result = await db.FixItTasks
            .Where(t => t.Owner == userName)
            .Where(t=>t.IsDone == false)
            .OrderByDescending(t => t.FixItTaskId).ToListAsync();

        timespan.Stop();
        log.TraceApi("SQL Database", "FixItTaskRepository.FindTasksByOwnerAsync", timespan.Elapsed, "username={0}", userName);

        return result;
    }
    catch (Exception e)
    {
        log.Error(e, "Error in FixItTaskRepository.FindTasksByOwnerAsync(userName={0})", userName);
        return null;
    }
}

Asyncこのコードでは、クエリがToListデータベースに送信されるメソッドであるため、メソッドのバージョンがあります。 メソッドと OrderByDescending メソッドはWhereクエリのみを構成しますが、メソッドはToListAsyncクエリを実行し、変数に応答をresult格納します。

まとめ

ここで説明する Web 開発のベスト プラクティスは、任意の Web プログラミング フレームワークとクラウド環境に実装できますが、ASP.NET と Windows Azure には簡単にするためのツールがあります。 これらのパターンに従うと、Web 層を簡単にスケールアウトでき、各サーバーがより多くのトラフィックを処理できるため、コストを最小限に抑えることができます。

次の章では、クラウドでシングル サインオン シナリオがどのように実現されるかについて説明します。

リソース

詳細については、次のリソースを参照してください。

ステートレス Web サーバー:

Cdn:

非同期プログラミング:

その他の Web 開発のベスト プラクティスについては、次のリソースを参照してください。