Начиная с версии 2.2. ASP.NET Core поддерживает режим внутрипроцессного размещения приложения (InProcess) в IIS, направленный на улучшение производительности кода. Рик Страл написал статью, в которой подробно исследовал эту тему. С тех пор прошло три года, теперь платформа ASP.NET Core добралась до версии 5.0. Как это повлияло на производительность ASP.NET Core-проектов на различных серверах?
Результаты исследования Рика Страла
Рик Страл в своей статье занимался тестирование ASP.NET Core-кода на Windows — в Kestrel и в IIS (в режимах InProcess и OutOfProcess). Его интересовало количество запросов в секунду, обрабатываемых системой. В результате он пришёл к выводу о том, что первое место по производительности получает использование IIS в режиме InProcess, второе — Kestrel, третье — IIS в режиме OutOfProcess.
Обзор эксперимента
Рик не провёл испытания, позволяющие выявить различия в выполнении ASP.NET Core-кода на Windows- и на Linux-серверах. А вопрос о том, что в 2021 году лучше выбрать для проектов, основанных на ASP.NET Core 5.0, интересует многих из тех, кого я знаю. Поэтому я решил, используя подход к тестированию, похожий на тот, которым пользовался Рик, узнать о том, сколько запросов в секунду может обработать ASP.NET Core 5.0-приложение на Windows и на Linux.
Тестовое окружение
Так как Windows 10, Ubuntu Desktop и другие настольные операционные системы не в полной мере отражают особенности сопоставимых с ними серверных дистрибутивов, я решил выбрать для тестов серверные версии соответствующих ОС. Это были свежеустановленные копии систем с последними патчами, перед выполнением тестов они были один раз перезагружены.
▍Windows-сервер:
- Провайдер: Microsoft Azure East Asia Region.
- ОС: Windows Server 2019 Data Center.
- Характеристики системы: B2S / 2 vCPU, 4GB RAM, Premium SSD.
- Окружение: IIS с поддержкой статического и динамического сжатия контента, отсутствие интеграции с ASP.NET 3.5 или 4.x, на сервере установлена платформа ASP.NET Core 5.0.2 Runtime.
Сведения о Windows-сервере
▍Linux-сервер
- Провайдер: Microsoft Azure East Asia Region.
- ОС: Ubuntu Server 20.04 LTS.
- Характеристики системы: B2S / 2 vCPU, 4GB RAM, Premium SSD.
- Окружение: включено использование BBR, установлены Nginx, Caddy и ASP.NET Core 5.0.2 Runtime.
Сведения о Linux-сервере
▍Инструменты для проведения тестов
Рик пользовался West Wind Web Surge, но этот инструмент доступен только на платформе Windows, а это нас не устроит. Я решил воспользоваться опенсорсным кросс-платформенным инструментом bombardier, о котором однажды писали в официальном .NET-блоге Microsoft.
▍Тестовое приложение
Я создал новый проект ASP.NET Core 5.0 Web API, в котором имеется лишь один метод:
[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
[HttpGet]
public string Get()
{
return $"Test {DateTime.UtcNow}";
}
}
Для того чтобы не усложнять проект, я не проверял JSON-сериализацию и другие механизмы. Вы, если вам это интересно, вполне можете исследовать их самостоятельно.
Проект скомпилирован с применением конфигурации Release и опубликован с использованием FDD. Настройки логирования оставлены в стандартном состоянии:
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
▍Методика тестирования
Я запускал проект, используя следующие конфигурации:
- Kestrel.
- IIS в режиме InProcess.
- IIS в режиме OutOfProcess.
- Обратный прокси Nginx.
- Обратный прокси Caddy.
Затем я применял bombardier. В течение 10 секунд, по 2 соединениям, велась работа с конечной точкой, доступной на localhost
. После «прогревочного» раунда испытаний я, друг за другом, проводил ещё 3 раунда и на основе полученных данных вычислял показатель количества запросов, обработанных исследуемой системой за секунду (Request per Second, RPS).
Пожалуйста, обратите внимание на то, что в идеальном случае лучше не использовать инструмент для исследования производительности, обращаясь с его помощью к локальным адресам. Дело в том, что при таком подходе операционная система вынуждена будет делить сетевые ресурсы между инструментом для тестирования и исследуемой программой. Но, так как сети в облачных окружениях не так стабильны, как localhost-подключение, я решил использовать в тестах именно локальное подключение. Это позволило исключить воздействие особенностей сети на результаты.
Результаты тестов
▍Windows + Kestrel
Средний RPS: 18808
Windows + Kestrel
▍Windows + IIS в режиме InProcess
Средний RPS: 10089
Windows + IIS в режиме InProcess
▍Windows + IIS в режиме OutOfProcess
Средний RPS: 2820
Windows + IIS в режиме OutOfProcess
▍Linux + Kestrel
Средний RPS: 10667
Linux + Kestrel
▍Linux + Nginx
Средний RPS: 3509
Linux + Nginx
▍Linux + Caddy
Средний RPS: 3485
Linux + Caddy
Итоги
Вот как выглядят результаты тестирования (от самой быстрой комбинации ОС и серверного ПО — до самой медленной):
- Windows + Kestrel (18808)
- Linux + Kestrel (10667)
- Windows + IIS в режиме InProcess (10089)
- Linux + Nginx (3509)
- Linux + Caddy (3485)
- Windows + IIS в режиме OutOfProcess (2820)
Мои результаты отличаются от тех, что получил Рик, тестируя ASP.NET Core 2.2-проект. В его тестах производительность IIS в режиме InProcess оказывалась выше, чем производительность Kestrel. Но сейчас Kestrel оказывается быстрее IIS в режиме InProcess, и это кажется вполне логичным и ожидаемым.
А вот неожиданностью для меня стало то, что производительность Windows-серверов c Kestrel оказалась выше производительности аналогичных Linux-серверов. Это меня удивило.
В режиме обратного прокси-сервера Nginx и Caddy, в общем-то, показывают одинаковую производительность. И та и другая конфигурации обходят IIS в режиме OutOfProcess.
Конечно, мой простой тест, в ходе которого сервер возвращает обычную строку, не позволяет проверить все нюансы производительности ASP.NET Core 5.0 и исследовать возможности каждого сервера. В реальных проектах присутствует множество факторов, которые воздействуют на производительность. План моего эксперимента не перекрывает все возможные сценарии использования ASP.NET Core 5.0, в нём, наверное, имеются какие-то недочёты. Если вы что-то такое заметите — дайте мне знать.
Дополнение
Мне сообщили, что в .NET 5 у DateTime.UtcNow
могут быть проблемы, касающиеся производительности. Я провёл повторные испытания, заменив эту конструкцию на Activity.Current?.Id ?? HttpContext.TraceIdentifier
. Получившиеся у меня результаты были выражены немного более высокими показателями, но общая картина осталась почти такой же.
А если увеличить число подключений с 2 до 125 — сервер Kestrel, и на Windows, и на Linux, способен дать гораздо более высокую пропускную способность.
Каким серверным ПО вы пользуетесь в своих проектах?
Автор: ru_vds