- PVSM.RU - https://www.pvsm.ru -
Что быстрее — ASP.NET Core [1]-приложение, развёрнутое в Docker-контейнере на Linux, или такая же программа, но запущенная на Windows-сервере, учитывая то, что всё это работает в службе приложений Azure [2]? Какая из этих конфигураций предлагает более высокий уровень производительности, и о каком «уровне производительности» можно говорить?
[3]
Недавно меня заинтересовали эти вопросы, после чего я решил сам всё проверить, сделав следующее:
В обоих случаях приложение собрано с использованием инструмента командной строки dotnet
в конфигурации Release
. Хостилось приложение с использованием кросс-платформенного сервера Kestrel [7] и было размещено за прокси-сервером, используемым службами Azure. В распоряжении каждого экземпляра приложения были ресурсы, обеспечиваемые планом обслуживания Standard S1, то есть — отдельная виртуальная машина. В ходе выполнения тестов я, кроме того, сравнил производительность ASP.NET Core-приложения, работающего в Docker-контейнере, с производительностью приложений, основанных на других стеках технологий, которые мне доводилось исследовать в последнее время (Go, Python 3.6.2, PyPy 3). В сервере Kestrel используется libuv [8] — поэтому мне интересно было сравнить его с uvloop [9], учитывая то, что последний является обёрткой для libuv и asyncio [10] (это — встроенный инструмент Python для создания конкурентного кода). Я думаю, что многие NET-разработчики гордятся [11] скоростью Kestrel и работой, проведённой инженерами Microsoft, но при этом забывают о том, что им стоило бы испытывать чувство благодарности и к libuv — С-библиотеке для организации асинхронного ввода-вывода, которая появилась до Kestrel и используется, кроме того, в Node.js [12] и в других подобных проектах. И, кроме того, стоит помнить о том, что, когда перед ASP.NET Core-приложениями находится IIS, нужно принимать во внимание некоторые дополнительные соображения [13].
Приложение основано на шаблоне веб-проекта, созданного с помощью dotnet [14]. Я специально старался как можно меньше его усложнять. В нём имеется один обработчик, возвращающий ответы двух типов:
Hello World
с отметкой времени.n
, представляющим собой число, находящееся в диапазоне от 1 до 100 — ответ с телом размером n
Кб. app.Run(async (context) =>
{
var request = context.Request;
var s = request.Query["s"];
if (string.IsNullOrEmpty(s)) {
// возврат простого Hello World
var now = DateTime.UtcNow;
await context.Response.WriteAsync($"Hello World, from ASP.NET Core and Net Core 2.0! {now.ToString("yyyy-MM-dd HH:mm:ss.FFF")}");
return;
}
// {...}
});
Для развёртывания проекта на Windows-машине я быстро создал проект в VSTS [15] (Visual Studio Team Services), настроил службы с использованием шаблонов ARM [16], собрал и развернул приложение с применением задач VSTS.
Настройка проекта
Работа с Windows-проектом в Microsoft Azure
В этом [17] GitHub-репозитории вы можете найти код приложения и ARM-шаблоны.
Образ Docker был подготовлен и опубликован с использованием того же подхода, о котором я уже писал [18], рассказывая о запуске образов Docker в Azure. Так как я уже об этом рассказывал, повторяться тут я не буду. Единственное, на что я хочу обратить ваше внимание — это то, что в одной группе ресурсов Azure нельзя смешивать планы служб приложений, рассчитанные на Linux и Windows. Поэтому для каждого из вариантов приложения я создал собственную группу ресурсов.
Работа с Linux-проектом в Microsoft Azure
Код приложения и файлы для создания образов Docker можно найти в этом [19] репозитории.
Мне нравится утилита Apache Benchmark [5] (ab). Ей удобно пользоваться и она выдаёт результаты, применимые при практической оценке производительности систем, такие, как количество запросов в секунду (Requests Per Second, RPS), время ответа на разных перцентилях (например — сведения о том, что 95% запросов обрабатывается в пределах n
мс, а 5% — в пределах m
мс, и так далее). Эта утилита идеально подходит для исследования производительности отдельных методов. Я выполнил несколько групп тестов, каждую — в разное время дня. План испытаний выглядел так:
Сценарий | Конфигурация |
Hello World | 5000 запросов, 150 одновременных пользователей |
Ответ с телом в 1 Кб | 5000 запросов, 150 одновременных пользователей |
Ответ с телом в 10 Кб | 2000 запросов, 150 одновременных пользователей |
Ответ с телом в 100 Кб | 2000 запросов, 150 одновременных пользователей |
# пример команды
ab -n 5000 -c 150 -l http://linuxaspcorehelloworld-dev-westeurope-webapp.azurewebsites.net/
Выходные данные ab выглядят примерно так:
This is ApacheBench, Version 2.3 <$Revision: 1757674 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking linuxaspcorehelloworld-dev-westeurope-webapp.azurewebsites.net (be patient)
Server Software: Kestrel
Server Hostname: linuxaspcorehelloworld-dev-westeurope-webapp.azurewebsites.net
Server Port: 80
Document Path: /
Document Length: 72 bytes
Concurrency Level: 150
Time taken for tests: 22.369 seconds
Complete requests: 5000
Failed requests: 0
Keep-Alive requests: 0
Total transferred: 1699416 bytes
HTML transferred: 359416 bytes
Requests per second: 223.53 [#/sec] (mean)
Time per request: 671.065 [ms] (mean)
Time per request: 4.474 [ms] (mean, across all concurrent requests)
Transfer rate: 74.19 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 40 489 289.9 425 3813
Processing: 42 170 227.6 109 3303
Waiting: 41 153 152.9 105 2035
Total: 106 659 359.2 553 4175
Percentage of the requests served within a certain time (ms)
50% 553
66% 650
75% 750
80% 786
90% 948
95% 1036
98% 1282
99% 1918
100% 4175 (longest request)
И, наконец, я собрал результаты воедино с использованием Python-скрипта, после чего посчитал средние показатели по всем тестам и построил графики двух видов:
В ходе выполнения тестовых сценариев «Hello World» и «Ответ с телом в 1 Кб» на серверы было отправлено около 250 тысяч запросов. Их количество для сценариев, в которых применялись ответы с телом размером 10 Кб и 100 Кб, находилось в районе 110 — 70 тысяч запросов. Эти показатели не выражены в точных цифрах, так как иногда инфраструктура Azure закрывает соединения (connection reset by peer), но количество проанализированных запросов, всё равно, является достаточно большим. Не обращайте особого внимания на абсолютные значения, приводимые ниже: они имеют смысл лишь в плане сравнения друг с другом, так как они зависят и от клиента, и от сервера. Результаты, показанные в следующей таблице, получены с использованием клиента, подключённого к интернету по Wi-Fi-сети.
Хост | Сценарий | RPS (среднее значение) | 95% запросов выполнено в пределах … мс |
Linux | Hello World | 232,61 | 1103,64 |
Linux | Ответ с телом в 1 Кб | 228,79 | 1129,93 |
Linux | Ответ с телом в 10 Кб | 117,92 | 1871,29 |
Linux | Ответ с телом в 100 Кб | 17,84 | 14321,78 |
Windows | Hello World | 174,62 | 1356,8 |
Windows | Ответ с телом в 1 Кб | 171,59 | 1367,23 |
Windows | Ответ с телом в 10 Кб | 108,08 | 2506,95 |
Windows | Ответ с телом в 100 Кб | 17,37 | 16440,27 |
Эти результаты позволяют сделать вывод о том, что, если тело ответа невелико, приложение, работающее в Docker-контейнере на Linux, гораздо быстрее обрабатывает HTTP-запросы, чем его версия, работающая в среде Windows. Разница между разными вариантами запуска приложения уменьшается по мере роста тела ответа, хотя, всё равно, Linux-вариант оказывается быстрее Windows-варианта. Такой результат может показаться удивительным, так как Windows-сервер, работающий в службе приложений Azure, представляет собой более зрелое решение, нежели Linux-сервер, работающий там же. С другой стороны, виртуализация Docker, в сравнении с другими технологиями виртуализации приложений, не отличается особой требовательностью к системным ресурсам. Возможно, имеются и другие отличия в конфигурациях, позволяющие Linux-хосту работать эффективнее, что особенно заметно при работе с ответами, тела которых невелики.
Сценарий | Linux, прирост RPS в сравнении с Windows |
Hello World | +33,21% |
Ответ с телом в 1 Кб | +33,33% |
Ответ с телом в 10 Кб | +9,1% |
Ответ с телом в 100 Кб | +2,7% |
Вот диаграммы, иллюстрирующие вышеприведённые данные.
Запросов в секунду, средний показатель (больше — лучше)
Время, в течение которого обрабатываются 95% запросов (меньше — лучше)
Время, в течение которого обрабатываются 95% запросов (меньше — лучше)
Вышеописанные испытания производительности были повторены с использованием инструментов Visual Studio Ultimate Web Performance. Клиентская система, в географическом смысле, располагалась там же, где и раньше, но в этот раз она была подключена к интернету по проводной сети. Вот исходный код тестов. В данном случае использовались следующие настройки:
Тестирование серверов с помощью Visual Studio Web Performance (оригинал [20])
Результаты тестов, проведённых с помощью Visual Studio Web Performance, отличаются от тех, что были проведены с помощью Apache Benchmark, но при этом Linux-система показала себя даже лучше, чем прежде. Различия в результатах испытаний можно объяснить следующими фактами:
Но, всё равно, допустимо напрямую сравнивать результаты испытаний только тогда, когда они выполнены с использованием одного и того же клиента, с применением одних и тех же инструментов и настроек.
Хост | Сценарий | RPS (среднее значение) | 95% запросов выполнено в пределах … мс |
Linux | Hello World | 649 | 340 |
Linux | Ответ с телом в 1 Кб | 622 | 380 |
Linux | Ответ с телом в 10 Кб | 568 | 370 |
Linux | Ответ с телом в 100 Кб | 145 | 1220 |
Windows | Hello World | 391 | 400 |
Windows | Ответ с телом в 1 Кб | 387 | 420 |
Windows | Ответ с телом в 10 Кб | 333 | 510 |
Windows | Ответ с телом в 100 Кб | 108 | 1560 |
Вот таблица со сравнением Linux- и Windows-вариантов приложения.
Сценарий | Linux, прирост RPS в сравнении с Windows |
Hello World | +65,98% |
Ответ с телом в 1 Кб | +60,72% |
Ответ с телом в 10 Кб | +70,57% |
Ответ с телом в 100 Кб | +34,26% |
Вот визуализация этих данных.
Запросов в секунду, средний показатель (больше — лучше)
Время, в течение которого обрабатываются 95% запросов (меньше — лучше)
Я могу провести сравнение Linux+Docker-варианта исследуемого приложения с приложениями, при создании которых использовались другие технологии, испытанные мной за последние дни, лишь используя сценарий «Hello, World». Но при этом не могу не отметить, что даже при таком походе производительность Windows-варианта выглядит слишком низкой. Думаю, что стандартная конфигурация Kestrel (например — количество потоков) не оптимизирована для планов Standard S1. Например — вот средние значения RPS, полученные для других стеков технологий, испытания которых проводились с использованием тех же настроек.
Стек технологий | Сценарий Hello World, RPS |
Go 1.9.1 net/http | ~1000, с пиками в ~1100 |
Python 3.6.1 uvloop, httptools | ~1000, с пиками в ~1200 |
Python 3.6.1 Sanic, uvloop | ~600, с пиками в ~650 |
PyPy 3, Gunicorn, Gevent, Flask | ~600, с пиками в ~650 |
Эти результаты не снижают ценности ранее выполненных испытаний, в ходе которых одно и то же ASP.NET Core-приложение исследовалось в средах Windows и Linux.
Развёртывание проектов в службе приложений Azure с использованием Linux и Docker не ухудшает производительности приложений, что идёт вразрез с тем, чего многие могли бы ожидать, учитывая то, что Windows-хостинг этой платформы представляет собой более зрелое решение. Применение Linux в Azure, на самом деле, выгоднее применения Windows, особенно — в тех случаях, когда речь идёт об обработке запросов, предусматривающих отправку ответов, тела которых имеют небольшие размеры.
Чем вы пользуетесь на серверах — Linux или Windows?
Автор: ru_vds
Источник [22]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/linux/364045
Ссылки в тексте:
[1] ASP.NET Core: https://docs.microsoft.com/ru-ru/aspnet/core/?view=aspnetcore-5.0
[2] службе приложений Azure: https://docs.microsoft.com/ru-ru/azure/app-service/overview-hosting-plans
[3] Image: https://habr.com/ru/company/ruvds/blog/555650/
[4] Standard S1: https://azure.microsoft.com/ru-ru/pricing/details/app-service/windows/
[5] Apache Benchmark: https://httpd.apache.org/docs/2.4/programs/ab.html
[6] Visual Studio Web Performance Test: https://msdn.microsoft.com/en-us/library/ms182551(v=vs.110).aspx
[7] Kestrel: https://docs.microsoft.com/ru-ru/aspnet/core/fundamentals/servers/kestrel?tabs=aspnetcore2x&view=aspnetcore-5.0
[8] libuv: https://en.wikipedia.org/wiki/Libuv
[9] uvloop: https://github.com/MagicStack/uvloop
[10] asyncio: https://docs.python.org/3/library/asyncio.html
[11] гордятся: https://www.ageofascent.com/2016/02/18/asp-net-core-exeeds-1-15-million-requests-12-6-gbps/
[12] Node.js: https://nodejs.org/en/
[13] соображения: https://weblog.west-wind.com/posts/2017/Mar/16/More-on-ASPNET-Core-Running-under-IIS
[14] dotnet: https://docs.microsoft.com/ru-ru/dotnet/core/tools/dotnet-new?tabs=netcore2x
[15] VSTS: https://www.visualstudio.com/team-services/
[16] шаблонов ARM: https://github.com/RobertoPrevato/ASPNetCoreHelloWorld/tree/master/webhelloworld/arm
[17] этом: https://github.com/RobertoPrevato/ASPNetCoreHelloWorld
[18] писал: https://robertoprevato.github.io/Running-Docker-applications-in-Azure/
[19] этом: https://github.com/RobertoPrevato/AzureDocker
[20] оригинал: https://raw.githubusercontent.com/RobertoPrevato/ASPNetCoreHelloWorld/master/PerformanceTests/load-test-settings.PNG
[21] Image: http://ruvds.com/ru-rub?utm_source=habr&utm_medium=perevod&utm_campaign=sravnenie_proizvoditelnosti_asp_net_core-proektov_na_linux_i_windows_v_sluzhbe_prilozhenij_azure
[22] Источник: https://habr.com/ru/post/555650/?utm_source=habrahabr&utm_medium=rss&utm_campaign=555650
Нажмите здесь для печати.