Web 開発のベスト プラクティス (Azure を使用したReal-World Cloud Apps の構築)
作成者 : Rick Anderson、 Tom Dykstra
Fix It プロジェクトのダウンロード または 電子書籍のダウンロード
Azure 電子書籍 を使用した Real World Cloud Apps の構築 は、Scott Guthrie が開発したプレゼンテーションに基づいています。 クラウド向けの Web アプリの開発を成功させるために役立つ 13 のパターンとプラクティスについて説明します。 電子書籍の詳細については、 最初の章を参照してください。
最初の 3 つのパターンは、アジャイル開発プロセスを設定することでした。残りはアーキテクチャとコードについてです。 これは、Web 開発のベスト プラクティスのコレクションです。
- スマート ロード バランサーの背後にあるステートレス Web サーバー。
- セッション状態を回避する (または回避できない場合は、データベースではなく分散キャッシュを使用します)。
- CDN を使用して 静的ファイル資産 (イメージ、スクリプト) をエッジキャッシュします。
- 呼び出しのブロックを回避するには、.NET 4.5 の非同期サポートを使用します。
これらのプラクティスは、クラウド アプリだけでなく、すべての 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 サイトのトラフィックを処理します。
インスタンス数を 3 に設定するか、1 に戻すのと同じように簡単に設定できます。 スケール バックすると、Windows Azure は時間単位ではなく分単位で課金されるため、すぐに節約を開始します。
また、CPU 使用率に基づいて Web サーバーの数を自動的に増減するように Windows Azure に指示することもできます。 次の例では、CPU 使用率が 60% を下回ると、Web サーバーの数は少なくとも 2 に減少し、CPU 使用率が 80% を超えると、Web サーバーの数は最大 4 まで増加します。
または、サイトが勤務時間中にのみビジー状態になることがわかっている場合はどうでしょうか。 日中に複数のサーバーを実行し、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 サーバー:
- Microsoft のパターンとプラクティス - 自動スケーリングのガイダンス。
- Windows Azure Web サイトでの ARR のインスタンス アフィニティの無効化。 Erez Benari によるブログ記事では、Windows Azure Web サイトのセッション アフィニティについて説明しています。
Cdn:
- FailSafe: スケーラブルで回復性の高いCloud Servicesの構築。 ウルリッヒ・ホーマン、マルク・メルキュール、マーク・シムズによる9部構成のビデオシリーズ。 1:34:00 以降のエピソード 3 の CDN ディスカッションを参照してください。
- Microsoft のパターンとプラクティス静的コンテンツ ホスティング パターン
- CDN のレビュー。 多くの CDN の概要。
非同期プログラミング:
- ASP.NET MVC 4 での非同期メソッドの使用。 Rick Anderson によるチュートリアル。
- Async と Await を使用した非同期プログラミング (C# と Visual Basic)。 非同期プログラミングの根拠、ASP.NET 4.5 での動作方法、実装するコードの記述方法について説明する MSDN ホワイト ペーパー。
- Entity Framework の非同期クエリと保存
- FailSafe: スケーラブルで回復性の高いCloud Servicesの構築。 ウルリッヒ・ホーマン、マルク・メルキュール、マーク・シムズによる9部構成のビデオシリーズ。 非同期プログラミングがスケーラビリティに与える影響については、エピソード 4 とエピソード 8 を参照してください。
- ASP.NET 4.5 で非同期メソッドを使用する魔法と重要なゴッチャ。 Scott Hanselman によるブログ投稿。主に、ASP.NET Web Forms アプリケーションでの非同期の使用に関する記事です。
その他の Web 開発のベスト プラクティスについては、次のリソースを参照してください。
- Fix it サンプル アプリケーション - ベスト プラクティス。 この電子書籍の付録には、Fix It アプリケーションに実装されたいくつかのベスト プラクティスが記載されています。
- Web 開発者チェックリスト