Управление потоками в asp.net core / kestrel
Я устраняю проблемы с производительностью / масштабируемостью приложения asp.net, которое мы перенесли на asp.net core 2.0. Наше приложение размещается на Azure в качестве службы приложений и слишком легко падает при любом умеренном трафике.
Одна вещь, которая озадачивает меня - это то, как обрабатываются несколько одновременных запросов. Из того, что я прочитал здесь, Kestrel использует несколько циклов обработки событий для обработки ваших запросов. Но фактический код пользователя обрабатывается в пуле потоков.net ( отсюда).
Итак, в качестве эксперимента - я создал новое приложение MVC asp.net core 2.0 и добавил довольно неприятный метод действий:
[AllowAnonymous]
public ActionResult Wait1()
{
System.Threading.Tasks.Task.Delay(1000).Wait();
return new StatusCodeResult((int)HttpStatusCode.OK);
}
Теперь, когда я нажимаю это на azure, я ожидаю, что если я отправлю, скажем, 100 запросов одновременно, то у меня все будет в порядке, потому что 100 запросов звучат как незначительная загрузка, верно? И ожидание произойдет в потоках пула потоков, верно?
Итак, я делаю это и получаю довольно плохие результаты - образец выделен красным:
Хм, не то, что я ожидал, около 50 секунд на запрос... Если, однако, я изменю частоту, чтобы запросы были разнесены на секунду, тогда время отклика будет хорошим - обратно чуть больше 1000 мс, как и следовало ожидать. Кажется, если я перехожу более 30 запросов одновременно, он начинает страдать, что мне кажется несколько низким.
Итак - я понимаю, что мой неприятный метод действия блокируется, но я ожидал, что он будет блокироваться в потоке пула потоков и, следовательно, сможет справиться с более чем 30-ю.
Является ли это ожидаемым поведением - и если да, то просто ли убедиться, что никакая работа, связанная с вводом-выводом, не выполняется без использования асинхронного кода?
1 ответ
Является ли это ожидаемым поведением - и если да, то просто ли убедиться, что никакая работа, связанная с вводом-выводом, не выполняется без использования асинхронного кода?
Исходя из моего опыта, кажется, что это как ожидаемое поведение. Мы могли бы получить ответ из этого блога.
Теперь предположим, что вы запускаете приложение ASP.Net в IIS, а ваш веб-сервер имеет в общей сложности четыре процессора. Предположим, что в любой данный момент времени есть 100 запросов для обработки. По умолчанию среда выполнения создаст четыре потока, которые будут доступны для обслуживания первых четырех запросов. Поскольку никакие дополнительные потоки не будут добавлены до истечения 500 миллисекунд, остальные 96 запросов должны будут ждать в очереди. По истечении 500 миллисекунд создается новый поток.
Как вы можете видеть, потребуется 100*500 мсек, чтобы справиться с нагрузкой.
Это хорошая причина для использования асинхронного программирования. При асинхронном программировании потоки не блокируются во время обработки запросов, поэтому четыре потока будут освобождены почти сразу.
Я рекомендую вам использовать асинхронный код для повышения производительности.
public async Task<ActionResult> Wait1()
{
await Task.Delay(TimeSpan.FromSeconds(15));
return new StatusCodeResult((int)HttpStatusCode.OK);
}
Я также нахожу другой поток, так что вы можете обратиться к нему.