Подтвердить что ты не робот

Многопоточный HttpListener с ожиданием 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, - это то, что правительство. область, в которой я работаю, требует крайне уменьшенной площади атаки.

4b9b3361

Ответ 1

Я сделал что-то подобное в https://github.com/JamesDunne/Aardwolf и провел несколько обширных тестов.

См. код https://github.com/JamesDunne/aardwolf/blob/master/Aardwolf/HttpAsyncHost.cs#L107 для реализации цикла основного события.

Я считаю, что использование Semaphore для управления количеством параллельных запросов GetContextAsync является самым лучшим подходом. По существу, основной цикл продолжает работать до тех пор, пока семафор не блокирует поток из-за достижения счетчика. Затем будет активировано N одновременных активных подключений. Каждый раз, когда соединение принимается, семафор освобождается, и новый запрос может занять его место.

Начальные и максимальные значения семафора требуют некоторой тонкой настройки в зависимости от нагрузки, которую вы ожидаете получить. Это тонкий баланс между количеством параллельных подключений, которые вы ожидаете, против среднего времени отклика, которое пожелают ваши клиенты. Более высокие значения означают, что большее количество соединений может поддерживаться еще при значительно более медленном среднем времени отклика; меньшее количество соединений будет отклонено. Более низкие значения означают, что меньше соединений можно поддерживать еще со значительно более быстрым средним временем отклика; больше соединений будет отклонено.

Я нашел, экспериментально (на моем оборудовании), что значения вокруг 128 позволяют серверу обрабатывать большое количество одновременных подключений (до 1,024) при приемлемом времени отклика. Протестируйте с помощью собственного оборудования и соответствующим образом настройте свои параметры.

Я также обнаружил, что один экземпляр WCAT не любит обрабатывать более 1024 подключений. Поэтому, если вы серьезно относитесь к нагрузочному тестированию, используйте несколько клиентских машин с WCAT против вашего сервера и не забудьте протестировать более быструю сеть, например. 10 GbE и что ограничения вашей ОС не замедляют вас. Обязательно проверяйте на SKU сервера Windows, потому что по умолчанию для SKU для ПК ограничено.

Резюме: Как вы пишете цикл принятия соединения, критически важно для масштабируемости вашего сервера.

Ответ 2

Технически вы правы. Чтобы сделать его масштабируемым, вы, вероятно, захотите одновременно запустить несколько запусков GetContextAsync (для тестирования производительности необходимо знать, сколько именно, но "несколько для каждого ядра", вероятно, правильный ответ).

Тогда, естественно, как отмечалось в комментариях; не используя IIS, вы должны быть достаточно серьезными в отношении безопасности для многих вещей, которые IIS дает вам "бесплатно".

Ответ 3

Я знаю, что я очень опаздываю на вечеринку по этому поводу, но я опубликовал библиотеку (источник здесь https://github.com/jchristn/WatsonWebserver) на NuGet который инкапсулирует асинхронный веб-сервер.