Pull to refresh
2700.13
RUVDS.com
VDS/VPS-хостинг. Скидка 15% по коду HABR15

Сравнение производительности ASP.NET Core-проектов на Linux и Windows в службе приложений Azure

Reading time8 min
Views10K
Original author: Roberto Prevato
Что быстрее — ASP.NET Core-приложение, развёрнутое в Docker-контейнере на Linux, или такая же программа, но запущенная на Windows-сервере, учитывая то, что всё это работает в службе приложений Azure? Какая из этих конфигураций предлагает более высокий уровень производительности, и о каком «уровне производительности» можно говорить?



Недавно меня заинтересовали эти вопросы, после чего я решил сам всё проверить, сделав следующее:

  • Подготовил простое ASP.NET Core-приложение, используя NET Core 2.0 и C#.
  • Развернул один экземпляр этого приложения в службе Standard S1 на Windows-хосте, расположенном в регионе Western Europe.
  • Развернул ещё один экземпляр этого приложения в службе Standard S1 с использованием Linux-хоста (регион Western Europe) и Docker-контейнера.
  • Для создания нагрузки на серверы использовал Apache Benchmark, запросы отправлялись из Варшавы (Польша) с клиентской системы, работающей под управлением Ubuntu 17.04 и подключённой к интернету по Wi-Fi.
  • Повторил испытания, воспользовавшись средством Visual Studio Web Performance Test. Запросы к исследуемым серверам выполнялись из того же города, но в данном случае роль клиента выполнял компьютер, на котором установлена Windows 10, подключённый к интернету через проводную сеть.
  • Проанализировал данные, полученные в ходе тестирования, и сравнил результаты.

В обоих случаях приложение собрано с использованием инструмента командной строки dotnet в конфигурации Release. Хостилось приложение с использованием кросс-платформенного сервера Kestrel и было размещено за прокси-сервером, используемым службами Azure. В распоряжении каждого экземпляра приложения были ресурсы, обеспечиваемые планом обслуживания Standard S1, то есть — отдельная виртуальная машина. В ходе выполнения тестов я, кроме того, сравнил производительность ASP.NET Core-приложения, работающего в Docker-контейнере, с производительностью приложений, основанных на других стеках технологий, которые мне доводилось исследовать в последнее время (Go, Python 3.6.2, PyPy 3). В сервере Kestrel используется libuv — поэтому мне интересно было сравнить его с uvloop, учитывая то, что последний является обёрткой для libuv и asyncio (это — встроенный инструмент Python для создания конкурентного кода). Я думаю, что многие NET-разработчики гордятся скоростью Kestrel и работой, проведённой инженерами Microsoft, но при этом забывают о том, что им стоило бы испытывать чувство благодарности и к libuv — С-библиотеке для организации асинхронного ввода-вывода, которая появилась до Kestrel и используется, кроме того, в Node.js и в других подобных проектах. И, кроме того, стоит помнить о том, что, когда перед ASP.NET Core-приложениями находится IIS, нужно принимать во внимание некоторые дополнительные соображения.

Подготовка веб-приложения


Приложение основано на шаблоне веб-проекта, созданного с помощью dotnet. Я специально старался как можно меньше его усложнять. В нём имеется один обработчик, возвращающий ответы двух типов:

  • При получении запроса без параметров — сообщение 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-машине


Для развёртывания проекта на Windows-машине я быстро создал проект в VSTS (Visual Studio Team Services), настроил службы с использованием шаблонов ARM, собрал и развернул приложение с применением задач VSTS.


Настройка проекта


Работа с Windows-проектом в Microsoft Azure

В этом GitHub-репозитории вы можете найти код приложения и ARM-шаблоны.

Развёртывание приложения на Linux-машине с использованием Docker-контейнеров


Образ Docker был подготовлен и опубликован с использованием того же подхода, о котором я уже писал, рассказывая о запуске образов Docker в Azure. Так как я уже об этом рассказывал, повторяться тут я не буду. Единственное, на что я хочу обратить ваше внимание — это то, что в одной группе ресурсов Azure нельзя смешивать планы служб приложений, рассчитанные на Linux и Windows. Поэтому для каждого из вариантов приложения я создал собственную группу ресурсов.


Работа с Linux-проектом в Microsoft Azure

Код приложения и файлы для создания образов Docker можно найти в этом репозитории.

Тестирование приложений с использованием Apache Benchmark


Мне нравится утилита Apache Benchmark (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-скрипта, после чего посчитал средние показатели по всем тестам и построил графики двух видов:

  • Количество запросов в секунду (Requests per seconds, RPS), обработанных сервером.
  • 95-й перцентиль времени ответа, другими словами — показатель, отвечающий на вопрос о том, в пределах какого количества миллисекунд будет дан ответ на 95% запросов.

Анализ результатов, полученных с помощью Apache Benchmark


В ходе выполнения тестовых сценариев «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 Web Performance


Вышеописанные испытания производительности были повторены с использованием инструментов Visual Studio Ultimate Web Performance. Клиентская система, в географическом смысле, располагалась там же, где и раньше, но в этот раз она была подключена к интернету по проводной сети. Вот исходный код тестов. В данном случае использовались следующие настройки:

  • Тесты выполнялись по 5 минут.
  • В начале количество пользователей равнялось 50.
  • Каждые 10 секунд количество пользователей увеличивалось на 10.
  • Максимальным количеством пользователей было 150.


Тестирование серверов с помощью Visual Studio Web Performance (оригинал)

Анализ результатов, полученных с помощью Visual Studio Web Performance


Результаты тестов, проведённых с помощью Visual Studio Web Performance, отличаются от тех, что были проведены с помощью Apache Benchmark, но при этом Linux-система показала себя даже лучше, чем прежде. Различия в результатах испытаний можно объяснить следующими фактами:

  • Инструменты VS Web Performance, вероятно, по-другому работают с соединениями.
  • Для выполнения тестов использовались разные клиенты, по-разному подключённые к интернету.

Но, всё равно, допустимо напрямую сравнивать результаты испытаний только тогда, когда они выполнены с использованием одного и того же клиента, с применением одних и тех же инструментов и настроек.
Хост Сценарий 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% запросов (меньше — лучше)

Сравнение с другими стеками технологий в Docker


Я могу провести сравнение 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?

Tags:
Hubs:
Total votes 48: ↑46 and ↓2+44
Comments8

Articles

Information

Website
ruvds.com
Registered
Founded
Employees
11–30 employees
Location
Россия
Representative
ruvds