Данная статья является переводом статьи Кевина Голдберга «A Performance Analysis of Python WSGI Servers: Part 2» dzone.com/articles/a-performance-analysis-of-python-wsgi-servers-part с небольшими дополнениями от переводчика.

image

Введение


В первой части этой серии Вы познакомились с WSGI и с шестью наиболее популярными по мнению автора WSGI-серверами. В этой части Вам будет показан результат анализа производительности этих серверов. С этой целью была создана специальная тестовая песочница.

Конкурсанты


Из-за нехватки времени исследование было ограничено шестью WSGI-серверами. Весь код с инструкциями по запуску для этого проекта размещен на GitHub. Возможно со временем проект будет расширяться и будут представлены анализы производительности для других WSGI-серверов. Но пока речь пойдёт о шести серверах:?

  1. Bjoern описывает себя как « сверхбыстрый WSGI-сервер» и может похвастаться тем, что это «самый быстрый, самый маленький и легкий WSGI-сервер». Мы создали небольшое приложение, использующее большинство параметров библиотеки по умолчанию.
  2. CherryPy - чрезвычайно популярный и стабильный фреймворк и WSGI-сервер. Этот небольшой скрипт использовался для обслуживания нашего образца приложения через CherryPy.
  3. Gunicorn был вдохновлен сервером Unicorn от Ruby (отсюда и название). Он скромно утверждает, что он «просто реализован, легок в использовании и довольно быстрый». В отличие от Bjoern и CherryPy, Gunicorn является автономным сервером. Мы создали его с помощью этой команды. Параметр «WORKER_COUNT» был установлен в два раза больше доступных ядер процессора, плюс один. Это было сделано на основании рекомендаций из документации Gunicorn.
  4. Meinheld - это высокопроизводительный WSGI-совместимый веб-сервер, который утверждает, что он легкий. Основываясь на примере, указанном на сайте сервера, мы создали своё приложение.
  5. mod_wsgi создан тем же создателем, что и mod_python. Подобно mod_python, он доступен только для Apache. Однако он включает инструмент под названием «mod_wsgi express», который создаёт минимально возможный инстанс Apache. Мы сконфигурировали и использовали mod_wsgi express с помощью этой команды. Чтобы соответствовать Gunicorn, мы настроили mod_wsgi т.о, чтобы создать worker-ов вдвое больше чем ядер процессора.
  6. uWSGI - полнофункциональный сервер приложений. Как правило, uWSGI сопрягается с прокси-сервером (например: Nginx). Однако, чтобы лучше оценить производительность каждого сервера, мы попытались использовать только голые серверы и создали двух worker-ов для каждого доступного ядра процессора.

Бенчмарк


Чтобы сделать тест максимально объективным, был создан Docker-контейнер для изоляции тестируемого сервера от остальной части системы. Также использование Docker-контейнера гарантировало, что каждый запуск начинается с чистого листа.

Сервер:


  • Изолирован в Docker-контейнере.
  • Выделено 2 ядра процессора.
  • Оперативная память контейнера была ограничена до 512 МБ.

Тестирование:


  • wrk, современный инструмент HTTP-бенчмаркинга, запускал тесты.
  • Серверы были протестированы в произвольном порядке с увеличением числа одновременных соединений в диапазоне от 100 до 10000.
  • wrk был ограничен двумя ядрами ЦПУ, не используемыми Docker.
  • Каждый тест длился 30 секунд и повторялся 4 раза.

Метрика:


  • Среднее количество постоянных запросов, ошибок и задержек предоставлялось wrk.
  • Встроенный в Docker, мониторинг показывал уровни использования ЦПУ и ОЗУ.
  • Самые высокие и самые низкие показания были отброшены, а остальные значения были усреднены.
  • Для любопытных мы отправили полный скрипт на GitHub.

Результаты


Все исходные показатели производительности были включены в репозиторий проекта, а также предоставлен сводный CSV-файл. Также для визуализации были созданы графики в среде Google-doc.

Зависимость RPS от числа одновременных соединенинй


На этом графике показано среднее количество одновременных запросов; Чем выше число, тем лучше.

image

image

  • Bjoern: Явный победитель.
  • CherryPy: Несмотря на то, что он написан на чистом Python, он был лучшим исполнителем.
  • Meinheld: Отличные показатели, учитывая скудные ресурсы контейнера.
  • mod_wsgi: Не самый быстрый, но производительность была последовательной и адекватной.
  • Gunicorn: Хорошая производительность при более низких нагрузках, но прослеживается борьба при большом количестве соединений.
  • uWSGI: Разочаровал плохими результатами.

ПОБЕДИТЕЛЬ: Bjoern

Bjoern


По количеству постоянных запросов Bjoern является очевидным победителем. Однако, учитывая, что цифры намного выше, чем у конкурентов, мы немного скептически настроены. Мы не уверены в том, что Bjoern действительно настолько ошеломляюще быстрый. Сначала мы тестировали серверы по алфавиту, и мы думали, что Bjoern получил несправедливое преимущество. Однако даже после запуска серверов в произвольном порядке сервера и повторного тестирования результат остался прежним.

uWSGI


Мы были разочарованы слабыми результатами uWSGI. Мы ожидали, что он окажется в лидерах. Во время тестирования мы заметили, что логи uWSGI печатает на экране, и первоначально мы объяснили отсутствие производительности дополнительной работой, которую выполнял сервер. Тем не менее, даже после добавленной опции «--disable-logging», uWSGI по-прежнему является самым медленным сервером.

Как упоминалось в руководстве uWSGI, оно обычно сопрягается с прокси-сервером, таким как Nginx. Однако мы не уверены, что это может объяснить такую ??большую разницу.

Задержка


Задержка — это количество времени, прошедшего между запросом и его ответом. Более низкие цифры — лучше.

image

  • CherryPy: Хорошо справлялся с нагрузкой.
  • Bjoern: В целом низкие задержки, но лучше работает при меньшем количестве одновременных соединений.
  • Gunicorn: хорош и последователен.
  • mod_wsgi: Средняя производительность, даже при большом количестве одновременных соединений.
  • Meinheld: В целом, приемлемая производительность.
  • uWSGI: uWSGI снова на последнем месте.

ПОБЕДИТЕЛЬ: CherryPy

Использование ОЗУ


Эта метрика показывает требования к памяти и «легкость» каждого сервера. Более низкие цифры — лучше.

image

  • Bjoern: Чрезвычайно легкий. Использует всего лишь 9 МБ ОЗУ для обработки 10 000 одновременных запросов.
  • Meinheld: Такой же как Bjoern.
  • Gunicorn: Умело справляется с высокими нагрузками с едва заметным потреблением памяти.
  • CherryPy: Первоначально нуждался в небольшом количестве оперативной памяти, но её использование стремительно увеличивалось с ростом нагрузки.
  • mod_wsgi: На более низких уровнях он был одним из наиболее интенсивных в памяти, но оставался довольно последовательным.
  • uWSGI: Очевидно, что у тестируемой нами версии проблемы с количеством потребляемой памяти.

ПОБЕДИТЕЛИ: Bjoern и Meinheld

Количество ошибок


Ошибка возникает, когда сервер падает, прерывается или истекает время запроса. Чем ниже, тем лучше.

image

Для каждого сервера мы рассчитали отношение общее отношение количества запросов к числу ошибок:

  • CherryPy: коэффициент ошибок около 0, даже при высоком количестве соединений.
  • Bjoern: Ошибки встречались, но это компенсировалось количеством обработанных запросов.
  • mod_wsgi: Хорошо работает с приемлемой частотой ошибок 6%.
  • Gunicorn: Работает с 9-процентной частотой ошибок.
  • uWSGI: Учитывая низкое количество запросов, которые он обслуживал, он оказался с 34-процентной частотой ошибок.
  • Meinheld: Упал на более высоких нагрузках, выбросив более 10 000 ошибок во время самого требовательного теста.

ПОБЕДИТЕЛЬ: CherryPy

Использование ЦПУ


Высокое использование ЦПУ не является хорошим или плохим, если сервер работает хорошо. Однако, это даёт некоторые интересные сведения о работе сервера. Поскольку использовались два ядра ЦПУ, максимальное возможное использование составляет 200 процентов.

image

  • Bjoern: однопоточный сервер, о чем свидетельствует его последовательное использование на 100% ЦПУ.
  • CherryPy: многопоточный, но застрял на 150-ти процентах. Это может быть связано с GIL Python.
  • Gunicorn: использует несколько процессов с полным использованием ресурсов ЦПУ на более низких уровнях.
  • Meinheld: однопоточный сервер, использующий ресурсы ЦПУ как Bjoern.
  • mod_wsgi: Многопоточный сервер использующий все ядра ЦПУ на протяжении всех измерений
  • uWSGI: очень низкое использование ЦПУ. Потребление ресурсов ЦПУ не превышает 50-ти процентов. Это одно из доказательств того, что uWSGI неправильно сконфигурирован.

ПОБЕДИТЕЛЬ: Нет, поскольку это скорее наблюдение в поведении, чем сравнение в производительности.

Заключение


Подведем итог! Вот некоторые общие идеи, которые можно почерпнуть из результатов каждого сервера:

  • Bjoern: Оправдывает себя как «супербыстрый, ультралегкий WSGI-сервер».
  • CherryPy: Высокая производительность, маленькое потребление памяти и маленькое количество ошибок. Неплохо для чистого Python.
  • Gunicorn: Хороший сервер для средних нагрузок.
  • Meinheld: Хорошо работает и требует минимальных ресурсов. Тем не менее, борется с более высокими нагрузками.
  • mod_wsgi: Интегрируется в Apache и отлично работает.
  • uWSGI: Очень разочаровал. Либо мы неправильно сконфигурировали uWSGI, либо версия, которую мы установили, имеет базовые ошибки.

Комментарии (2)


  1. vodopad
    21.10.2018 20:49

    Не делайте одновременно синие и голубые линии, пожалуйста. Очень трудно различить цвета, например, в тесте про потребление ОЗУ.

    upd: это перевод, прошу прощения.


  1. MadWombat
    24.10.2018 11:14

    Я так понимаю, что у uWSGI основной метод работы это его собственный протокол который нативно поддерживается Nginx через директиву uwsgi_proxy. А с HTTP он может работать и не очень. Что впрочем существенный недостаток. Но интересно было бы посмотреть как такой же тест работает через прокси.