アプリケーションレベルのキューイング / ウェブサイトのトラフィック管理 質問する

アプリケーションレベルのキューイング / ウェブサイトのトラフィック管理 質問する

当社には、年間を通じて数回、非常に高いトラフィックが発生すると予想される Web サイト アプリケーションがあります。現在、当社では、大量のリクエストによって Web アプリケーション サーバーが飽和状態になるのを防ぐため、混雑時にユーザーを「保留」ページにリダイレクトするサード パーティの負荷分散ソフトウェアを導入しています。

今後は、このプロセスをより細かく制御し、何らかの仮想キューを実装したいと考えています。現在のロード バランサにはキューイング機能がなく、レート制限に基づいてトラフィックの通過を許可するだけです。これはランダムであり、ページを更新するタイミング (または自動更新) によって運が左右されます。

これについてオンラインでいくつか読んでみましたが、非常に基本的な仮想HTTPリクエストキューの実装方法についての実装の詳細はほとんど見つかりませんでした。もちろん、これを本格的なサービスとして提供している企業もあります。キューイットそしてネットプリセプトしかし、これらは現在のニーズには過剰であるように思われます(そして非常に高価です)。

問題の Web アプリケーションは、ASP.Net MVC で作成されています。現時点では「キューの優先順位」などの高度な機能は必要ないことを念頭に置き、などを使用して、静的キュー マネージャー クラスを使用した非常に基本的な概念実証を作成しましたConcurrentQueue<T>が、これが有効でスケーラブルなアプローチであるかどうか疑問に思っています。これは、メイン アプリケーション レイヤーの一部にできるものなのでしょうか。それとも、別々にしておくべきでしょうか。この種の機能を ASP.Net MVC アプリに実装する方法に関する技術的なノウハウを持っている人はいますか。


編集: これまでの回答に感謝します。回答のほとんどは、キャッシュについて非常に詳しく説明しているようです。これは、ASP.Net Web キャッシュ、ロード バランサー レベルでの全ページ要求のキャッシュ、AppFabric を使用したオブジェクト キャッシュを使用して、当社の Web サイトですでに (非常に) 頻繁に採用されています。

キューを管理できる理由は、プロセスが非常にデータベースへの書き込みが多い. 私たちは、Web サイトを通じて特定の製品の注文を事実上作成しています。つまり、これらの DB トランザクションは、直前の在庫確認などを考慮しています。ここでパフォーマンスの問題が発生するため、何らかのキューイング システムを実装する必要があります。

データベース サーバーにさらに多くのリソースを投入するのは現実的な選択肢ではありません。私は、この種のキューイング システム (C# またはその他) の技術的な実装の詳細を本当に探しています。これが最初に明確にされていなかった場合は申し訳ありません。

ベストアンサー1

アプリケーションのパフォーマンスを測定する際に、次の点を考慮していますか?

  1. キャッシング
  2. セッションレス コントローラ
  3. 非同期コントローラ

出力キャッシュ:

おそらくMVC3の最も便利な機能(パフォーマンス面)は出力キャッシュです。最大のパフォーマンスヒットは、アプリケーションが実際にデータを取得し、それに対して計算を行い、データを返す必要があるときに実際に発生します。出力キャッシュはこれらの結果をキャッシュできるため、データベースにアクセスすることなく直接返すことができます。特に複雑なクエリを実行する場合、これによりサーバーの負荷が大幅に軽減されます (実際、Web アプリケーションにキャッシュを慎重に実装することで、サーバーの負荷を 90% も軽減できます)。

namespace MvcApplication1.Controllers
{
     public class DataController : Controller
     {
          [OutputCache(Duration=10)]
          public string Index()
          {
               return DateTime.Now.ToString("T");    
          }
     }
}

セッションレス コントローラー:

セッション状態が無効になっているコントローラーは、セッション状態を必要としないコントローラーに最適化を提供します。ステートレス コントローラーは、セッションの概念を必要としない状況を対象としています。

デフォルトでは、ASP.NET パイプラインは同じセッションに属する要求を同時に処理しません。要求はシリアル化され、受信順にキューに入れられるため、並列ではなくシリアルに処理されます。つまり、要求が進行中のときに同じセッションから別の要求が到着すると、その要求はキューに入れられ、最初の要求が終了したときにのみ実行が開始されます。

例を見てみましょう。セッション状態を有効にして、サーバーに 3 つの非同期 AJAX 要求を行うページです (セッションは実際に使用する必要があることにも注意してください。ASP.NET は、セッション状態が有効になっている場合でも、使用しない場合は要求をシリアル化しないほど賢いからです)。

JQuery

$(document).ready(function () {
    //Make 3 concurrent requests to /ajaxtest/test
    for (var i = 0; i < 3; i++) {       
        $.post("/ajaxtest/test/" + i,
            function (data) {                       
                //Do something with data...
            },
            "json");
    }
});

コントローラー - アクションメソッド

public class AjaxTestController : Controller
{       
    [HttpPost]
    public JsonResult Test(int? id)
    {
        Thread.Sleep(500);
        return Json(/*Some object*/);
    }
}

ここに画像の説明を入力してください

ネットワーク プロファイルでシリアル化されたリクエストの効果を確認できます。各リクエストは、前のリクエストよりも約 500 ミリ秒長くかかります。つまり、これらの AJAX 呼び出しを非同期に行うことによるメリットが得られないということです。AjaxTestController のセッション状態を無効にしたプロファイルをもう一度見てみましょう ([SessionState] 属性を使用)。

[SessionState(SessionStateBehavior.Disabled)]
public class AjaxTestController : Controller
{       
    //...As above
}

ここに画像の説明を入力してください

ずっと良くなりました! 3 つのリクエストが並行して処理され、完了までに最初の例の 1500 ミリ秒ではなく合計 500 ミリ秒かかることがわかります。

非同期コントローラー:

まず、コントローラーは 1 つ以上の外部 I/O 呼び出し (SQL データベース呼び出しや Web サービス呼び出しなど) を開始します。それらの完了を待たずに、スレッドを ASP.NET ワーカー スレッド プールに解放し、他の要求を処理できるようにします。

その後、すべての外部 I/O 呼び出しが完了すると、基盤となる ASP.NET プラットフォームはプールから別の空きワーカー スレッドを取得し、それを元の HTTP コンテキストに再接続して、元の要求の処理を完了させます。

ここに画像の説明を入力してください

トラフィック量が多い場合の応答時間を測定するにはどうすればよいでしょうか?

以下の内容をこのリンクからコピーしました。リンクが壊れることもあるので、重要な部分をここに残しました。詳細についてはこのリンクを確認してください。

非同期コントローラーがさまざまなレベルのトラフィックにどのように応答するか、また、単純な同期コントローラーとどのように比較されるかを理解するには、2 つのコントローラーを含むサンプル MVC を作成します。長時間実行される外部をシミュレートするために、両方のコントローラーは完了までに 2 秒かかる SQL クエリを実行し (SQL コマンド WAITFOR DELAY '00:00:02′ を使用)、同じ固定テキストをブラウザーに返します。1 つは同期的に実行し、もう 1 つは非同期的に実行します。

別の例として、特定の URL に大量のトラフィックが集中する状況をシミュレートするシンプルな C# コンソール アプリケーションを確認できます。このアプリケーションは、同じ URL を何度も要求し、最後の数回の応答時間の平均を計算します。最初は 1 つのスレッドで実行しますが、その後、30 分間で同時スレッドの数を徐々に 150 に増やします。このツールを自分のサイトで実行したい場合は、C# ソース コードをダウンロードできます。

結果は、非同期リクエストのパフォーマンスに関するいくつかの点を示しています。平均応答時間と同時リクエスト数の関係を示す次のグラフをご覧ください (応答時間が短いほど優れています)。

ここに画像の説明を入力してください

これを理解するには、まず、ASP.NET MVC アプリケーションのワーカー スレッド プールの最大数を、人為的に低く設定したことをお伝えする必要があります。私のサーバーのスレッド プールの最大サイズは、実際には 200 に設定されています (より合理的な制限)。ただし、この値を減らすと、結果がより明確になります。ご覧のとおり、十分なワーカー スレッドがある限り、同期要求と非同期要求のパフォーマンスはまったく同じです。なぜ同じではないのでしょうか。ただし、スレッド プールが使い果たされると (クライアントが 50 を超えると)、同期要求はキューを形成して処理する必要がありました。基本的なキュー理論によると、キューで待機する平均時間は、次の式で表されます。

ここに画像の説明を入力してください

そして、これはまさにグラフに表示されているものです。キュー時間は、キューの長さに比例して増加します。(数式を使用したことをお詫びします。時々、自分の中の数学者を抑えられないのです。問題になったらセラピーを受けます。) ただし、非同期要求は、それほど早くキューを開始する必要はありませんでした。待機中にワーカー スレッドをブロックする必要がないため、スレッド プールの制限は問題になりませんでした。では、なぜ 100 を超えるクライアントがある場合にキューを開始したのでしょうか。これは、ADO.NET 接続プールが、デフォルトで同時接続 100 に制限されているためです。

これがお役に立てば幸いです。

おすすめ記事