web-dev-qa-db-ja.com

マルチスレッドのHttpListenerとawait asyncとタスク

これは、マルチスレッド化されたスケーラブルなHttpListenerの良い例でしょうか?

これは、たとえば、本当のIISがそれを行う方法ですか?

public class Program
{
    private static readonly HttpListener Listener = new HttpListener();

    public static void Main()
    {
        Listener.Prefixes.Add("http://+:80/");
        Listener.Start();
        Listen();
        Console.WriteLine("Listening...");
        Console.WriteLine("Press any key to exit...");
        Console.ReadKey();
    }

    private static async void Listen()
    {
        while (true)
        {
            var context = await Listener.GetContextAsync();
            Console.WriteLine("Client connected");
            Task.Factory.StartNew(() => ProcessRequest(context));
        }

        Listener.Close();
    }

    private static void ProcessRequest(HttpListenerContext context)
    {
        System.Threading.Thread.Sleep(10*1000);
        Console.WriteLine("Response");
    }
}

特に、IISに依存しないスケーラブルなソリューションを探しています。代わりにhttp.sys(httplistenerクラス)のみ-iISに依存しない理由は、政府によるものです。私が働いているエリアでは、攻撃の表面積を大幅に減らす必要があります。

27
halivingston

私は https://github.com/JamesDunne/Aardwolf で同様のことを行い、これについていくつかの広範なテストを行いました。

コアイベントループの実装については、コード https://github.com/JamesDunne/aardwolf/blob/master/Aardwolf/HttpAsyncHost.cs#L107 を参照してください。

Semaphoreを使用して、アクティブな同時GetContextAsyncリクエストの数を制御するのが最善の方法であることがわかりました。基本的に、カウントに達したためにセマフォがスレッドをブロックするまで、メインループは実行を続けます。次に、N個の同時「接続受け入れ」がアクティブになります。接続が受け入れられるたびに、セマフォが解放され、新しい要求が発生します。

セマフォの初期値と最大カウント値は、受け取ると予想される負荷に応じて、いくつかの微調整が必​​要です。これは、予想される同時接続数とクライアントが望む平均応答時間の間の微妙なバランスをとる行為です。値が大きいほど、より多くの接続を維持できますが、平均応答時間がはるかに遅くなります。拒否される接続が少なくなります。値が小さいほど、維持できる接続数は少なくなりますが、平均応答時間がはるかに速くなります。より多くの接続が拒否されます。

私は実験的に(私のハードウェア上で)128サーバーが許容可能な応答時間で大量の同時接続(最大1,024)を処理できるようにします。独自のハードウェアを使用してテストし、それに応じてパラメーターを調整します。

また、WCATの単一のインスタンスでは、1,024を超える接続自体を処理することは望ましくないこともわかりました。したがって、負荷テストに真剣に取り組んでいる場合は、サーバーに対してWCATを使用して複数のクライアントマシンを使用し、高速ネットワーク(例: 10 GbEであり、OSの制限によって速度が低下することはありません。デスクトップSKUはデフォルトで制限されているため、必ずWindows Server SKUでテストしてください。

概要:接続受け入れループの記述方法は、サーバーのスケーラビリティにとって重要です。

22
James Dunne

技術的にはあなたが正しいです。スケーラブルにするには、複数のGetContextAsyncを同時に実行する必要があります(パフォーマンステストでは正確にいくつあるかを知る必要がありますが、「コアごとにいくつか」がおそらく正しい答えです)。

そして当然、コメントで指摘されているように; IISを使用しないことは、多くのことにセキュリティについて真剣に取り組む必要があることを意味しますIISは「無料」で提供します。

5
Cellfish

私はこれでパーティーに途方もなく遅れていることを知っていますが、非同期Webサーバーをカプセル化するライブラリをNuGetに公開しました(ソースはここ https://github.com/jchristn/WatsonWebserver )。

1
joelc