nginx unit что это
Nginx Unit
В рамках заметки разбираемся с сервером приложений Nginx Unit и запускаем на нём простой сайт на WordPress.
Готовое окружение.
Оговоримся сразу — допустим, у нас уже есть сервер на CentOS 7, где установлены Nginx, PHP 5.4 (и это печально, да) и MariaDB. Установка этого ПО описана в тысячах разных заметок в сети, а админы и вовсе имеют уже либо свои инструменты для сетапа такого стека, либо ставят его почти с закрытыми глазами. Так что, для данной заметки, будем считать, что сервисы у нас уже стоят.
Кроме того, на сервере создан пользователь wp, с домашней директорией /usr/share/nginx/html/wp и загруженной в неё CMS WordPress. В данный момент, при обращении к адресу http://159.69.11.239/wp/index.php браузер предлагает скачать файл. Попробуем сделать так, что бы PHP на сайте заработал с помощью Nginx Unit.
Установка Nginx Unit.
Для установки сервера приложений, добавим в систему соответствующий репозиторий:
Установим нужные нам пакеты:
И убедимся что PHP для юнита установился и работает корректно. Для этого запустим сервис и загрузим в него пример конфига:
Теперь «постучим» curl’ом на http://localhost:8300/ И если всё настроено верно, получим выхлоп phpinfo();
Убедившись что всё в порядке, попробуем запустить наш сайт.
Настройка Nginx Unit.
Для запуска ресурса, в первую очередь, нам нужно создать конфигурационный файл, в котором, в json формате обязательно должны быть описаны две директивы — listeners и applications.
В рамках applications, мы описываем наше приложение — его название, язык на котором оно написано, директория, в которой оно работает, лимиты на количество его копий, пользователь и группу, от имени которого будет выполняться работа. Простейшее описание для wordpress будет таким:
В listeners мы описываем способ связи с нашим приложением. В нашем случае, конфиг будет выглядеть примерно так:
Собираем конфиг в одно целое и получаем:
Сюда было добавлено ещё одно приложение direct_php и listener для него. Они так же будут использованы при подключении юнита в nginx далее.
Сохраняем полученный конфиг в файл /usr/share/nginx/unit/wp.conf, а затем, с помощью curl запроса отправляем конфигурацию в сокет юнита:
Убедимся, что конфигурация загружена. Для этого, выведем всю конфигурацию командой:
Либо конфигурацию конкретного приложения:
Если мы захотим удалить конфигурацию, это можно сделать командой:
Нам остаётся подключить созданный unit в конфиге nginx и протестировать работу сайта.
Настраиваем Nginx.
Так как я делаю всё на тестовом сервере, я просто переименую дефолтный конфиг и буду работать с ним.
Два upstream, указывающие на запущенные нами юниты, и несколько базовых location, которые нужны для запуска WP сайта. Сохраняем конфиг, проверяем что ошибок не допустили и перезапускаем nginx:
В браузере переходим по адресу http://159.69.11.239/ и видим приглашение к установке CMS. Ставим, настраиваем и проверяем работу нашего тестового сайта. Если всё было сделано верно — постинг, добавление тем, плагинов, управление настройками сайта и т. п. должны работать без проблем.
Промежуточный итог.
Здорово, но остаюсь на PHP-FPM. Во всяком случае пока что. Причин тому несколько — в основном мне приходится работать с написанным на PHP, а для этого fpm на сегодняшний день, в сравнении с unit куда более гибкий инструмент. Кроме того, смущает невозможность использования PHP выше версии 5.4 на CentOS при установке ПО из пакетов.
Очень надеюсь что в будущем, по мере развития юнита, будут добавлены и новые возможности, и поддержка других версий PHP, а пока что, в проде у меня продолжает свою работу PHP-FPM.
8 thoughts on “ Nginx Unit ”
Gpg check зачем отключать в конфиге репозиттрия?!
Dynamic Application Server
NGINX Unit is a dynamic application server, capable of running beside NGINX Plus and NGINX Open Source or standalone. NGINX Unit supports a RESTful JSON API, deploys configuration changes without service disruptions, and runs apps built with multiple languages and frameworks. Designed from scratch around the needs of your distributed applications, it lays the foundation for your service mesh.
The Lightweight, Open Source App Server Designed for Today’s Dynamic and Distributed Apps
Wondering how an app server is different from a web server?
Why Use NGINX Unit?
Configure your applications in real time – NGINX Unit is tailored to the demands of modern microservices. Make one change and apply to all.
NGINX Unit is a polyglot app server, a reverse proxy, and a static file server, available for Unix‑like systems. It was built by NGINX team members from scratch to be highly efficient and fully configurable at runtime.
Avoid the requirements and headaches associated with multiple application servers. NGINX Unit supports a single configuration stack.
Dynamically adjust to your applications’ needs:
NGINX Unit is a polyglot app server, a reverse proxy, and a static file server, available for Unix‑like systems. It was built by NGINX team members from scratch to be highly efficient and fully configurable at runtime.
Dynamically adjust to your applications’ needs:
NGINX Unit is a polyglot app server, a reverse proxy, and a static file server, available for Unix‑like systems. It was built by NGINX team members from scratch to be highly efficient and fully configurable at runtime.
Ожидание длиной в 15 лет. Nginx Application Server
Начиная с момента появления Nginx в 2004 году, мы все задавались вопросом: когда же на nginx можно будет запускать приложения? Мы запускали PHP в php-fpm и на апаче, запускали Python через uWSGI, иногда жили с Apache, а если нам нужны были разные версии PHP — жили с зоопарком из FPM-ов.
Только что на конференции NginxConf в Портленде Nginx, Inc. объявил о запуске Nginx Application Platform. ITSumma тестировала один из его компонентов, собственно сам Application Server под названием Nginx Unit с закрытой версии. В этом посте мы расскажем о том, как выглядит Nginx Unit, и как на нем запускать приложения.
Nginx Unit — это сервер приложений для веба, позволяющий запускать веб-приложения, написанные на различных языках программирования (php, python, go). Этот инструмент достаточно легок и позволяет на лету переконфигурировать настройки и количество приложений по мере необходимости при разработке.
Поддерживаемые на текущий момент платформы:
— Python 2.6, 2.7, 3
— PHP 5, 7
— Go 1.6 or later
Важная и крутая возможность для людей с зоопарком платформ: разные версии одной и той же платформы можно запустить в рамках одного конфига, одного аппсервера — прощай, зоопарк PHP-FPM-ов.
→ Исходный код проекта загружен на Гитхаб.
Что классно и интересно: ребята загрузили на Гитхаб код начиная с первого коммита и обещают принимать пулл-реквесты в классическом для Гитхаба стиле. Среди всего прочего можно посмотреть историю, логику и стиль разработки — очень интересно.
Установка
Важно: текущая версия все еще бета, с огромным количеством отладочного кода, который добавляет свой оверхед. В следующих версиях обещают значительную оптимизацию, которая должна переплюнуть текущие апп-серверы по производительности.
Пакеты сейчас доступны для CentOS 7.0 и Ubuntu 16.04 LTS
Установка для CentOS 7
1. Создайте файл /etc/yum.repos.d/unit.repo со следующим содержимым:
2. Запустите установку пакета:
Установка для Ubuntu 16.04
2. Добавьте ключ в связку ключей apt. После этого не должно быть оповещений об отсутствующем PGP-ключе во время установки Unit.
3. Добавьте в конец файла /etc/apt/sources.list строки:
Nginx Unit состоит из нескольких служебных процессов (master/controller/router) и непосредственно самих процессов-приложений. Конфигурация производится через REST API, через юникс сокет unit.control.sock.
Получение текущего конфига
Конфигурация состоит из набора приложений (application) и воркеров (listener).
Запуск приложения
Рассмотрим запуск приложения на примере запуска «1С-Битрикс» и Laravel:
Фронтэндом выступает классический nginx, а бэкэндом — Nginx Unit. Сейчас каждое «приложение» Nginx Unit для PHP подразумевает одну точку входа. В случае с Битриксом их может быть две — urlrewrite.php и index.php, соответственно в бете — нужно либо объединить эту логику в один файл в коде, либо запускать два приложения. В ближайших версиях Nginx Unit ребята обещают сделать роутинг, чтобы избежать этой проблемы.
Конфигурация для Laravel:
Конфигурация для «1С-Битрикс»:
Для замены конфигурации запускаем
(По-умолчанию — сокет, проксировать с сокета в TCP порт можно посредством nginx.)
В настоящий момент конфигурацию надо подгружать при запуске апп-сервера, в следующих версиях Unit будет сохранять загруженную конфигурацию при перезапуске.
Сначала перечисляем приложения, при этом для каждого приложения указываем версию интерпретатора. В качестве точки входа можно указать параметр index (и тогда скрипт будет браться из строки запроса), или, в случае точки входа, script — и тогда запросы будут идти на конкретный скрипт. Опять же, обратите внимание, для «1С-Битрикс» запускаются два приложения:
Затем апы вешаются на порты:
Мы все ждали этого довольно давно, однако давайте все-таки рассмотрим случаи, когда Unit принесет серьезное преимущество:
Nginx unit что это
NGINX Unit: новый application-сервер для Ruby
Кратко говоря: NGINX Inc. выпустил поддержку Ruby для нового многоязычного сервера приложений NGINX Unit. Что это дает веб-приложениям Ruby? Обратить ли внимание на NGINX Unit? (1653 слова/10 минут чтения)
Для Ruby появился новый сервер приложений — NGINX Unit. Как вы догадались по названию, это проект NGINX Inc., опенсорсной некоммерческой компании, которой принадлежит веб-сервер NGINX. Осенью 2017 года они объявили, что винегрет серверов приложений (для Ruby — Puma, Unicorn и Passenger) будет заменен единым сервером NGINX Unit. NGINX Unit также работает с Python, Go, PHP и Perl.
Главная идея — упростить администрирование микросервисов. Один процесс NGINX Unit запускает любое количество приложений с любым количеством языков — например, единственный сервер NGNX Unit запускает штук 5 приложений Ruby и для каждого создает свою среду. Или можно запустить приложения Ruby и Python параллельно. Сочетания ограничены только системными ресурсами.
Увы, инфопространство «микросервиса» заспамлено маркетологами. (*Мне не нравится, когда программные проекты позиционируют себя как «современные». Это похоже на «подтасовку» всех существовавших программных проектов в этом проблемном пространстве, говоря, что все они старые и сломанные, а этот способ — новый. Почему этот способ лучше никогда не объясняется. Такой маркетинг заставляет разработчиков программного обеспечения бояться устаревания их навыков, вместо того, чтобы делать что-то существенное.) Они запросто смешивают в одном предложении «динамический», «модульный», «ресурсоемкий» — и «хаотичный», «цельный», «изящный». Мы попробуем прорваться через маркетинг и добраться до сути NGINX Unit.
Прежде чем говорить об архитектуре и особенностях NGINX Unit, убедимся, что все понимают разницу между сервером приложений и веб-сервером. Веб-сервер подключается к клиентам через HTTP и отдает статические файлы или прокси на другие HTTP-серверы, т.е. действует как посредник. Сервер приложений запускает и исполняет языковую среду. В Ruby эти явления не до конца разделены. Основные серверы приложений служат веб-серверами, а вот Nginx и Apache немогут служить серверами приложений. Nginx UNIT — одновременно веб-сервер и сервер приложений.
NGINX Unit запускает четыре процесса: основной (main), маршрутизация (router), контроллер (controller) и обработка (application). Что такое обработка, очевидно из названия: это среда выполнения Ruby, запускающая Rails приложение. Специфику NGINX Unit определяет реализация и взаимодействие маршрутизации, контроллера и обработки.
Основной процесс создает процессы маршрутизации и обработки. Собственно только этим он и занимается. Однако процессы обработки в NGINX Unit динамичны: на работающем сервере можно менять количество запущенных процессов, версию Ruby, и даже запускать новые приложения. Какие приложения запустить, говорит основному процессу контроллер.
Контроллер (он единственный, как и основной процесс) выполняет две задачи: предоставить API конфигурации JSON по HTTP и настроить основной процесс и процесс маршрутизации. Пожалуй, это самый интересный аспект NGNIX Unit для Ruby. Вместо возни с файлами конфигурации вы передаете объекты JSON в процесс управления. Вот такой файл json:
… мы можем передать контроллеру NGINX Unit (при условии, что наш сервер NGINX Unit слушает порт 8443):
… и создать новое приложение Ruby.
Объект конфигурации JSON NGINX Unit разделен на получателя запросов и приложение. Приложение исполняется, а получатель запросов слушает внешний мир (т.е. порт, на котором он висит).
Изменять конфигурацию приложения и получателя запросов нужно без пауз. Например, для «горячего развертывания» новой версии приложения добавим новое приложение в конфигурацию:
А затем переключим получателя запросов на новое приложение:
Переход (предположительно) прошел гладко, и клиенты ничего не заметили. Это похоже на «поэтапный перезапуск» Puma. При поэтапном перезапуске в Puma рабочие процессы перезапускаются по одному, пока оставшиеся рабочие процессы принимают запросы. Puma использует управляющий сервер (под контролем pumactl ). Однако, в отличие от Puma, при «горячей перезагрузке» NGINX Unit не будет двух версий приложения, одновременно принимающих запросы.
В поэтапном перезапуске Puma приложение имеет шесть рабочих процессов. В процессе поэтапного перезапуска три рабочих процесса запускают старый код, остальные три — новый код. Это может вызвать проблемы, например, с изменениями схемы базы данных. Перезапуски NGINX Unit происходят «одновременно», поэтому работают две версии кода, но в любой момент времени принимает запросы только одна.
Этот функционал полезен тем, кто использует собственное приложение Ruby на сервисе AWS, где нужно контролировать развертывание. Пользователям Heroku это не нужно, в предзагрузочной среде Heroku уже предусмотрено «горячее развертывание». Однако, эти средства работают по-разному. Heroku создает новый виртуальный сервер и переключается на него, а NGINX Unit меняет процессы на той же машине неразличимо для клиента.
Процесс маршрутизации делает то, что заложено в названии: превращает HTTP-подключения клиентов в запросы к процессам веб-приложений. NGINX утверждает, что один маршрутизатор Unit может обрабатывать тысячи одновременных подключений. Маршрутизатор работает так же, как веб-сервер NGINX, и имеет ряд рабочих потоков для приема, буферизации и парсинга входящих подключений.
Это одна из самых интересных частей NGINX Unit. Серверам приложений Ruby сложно работать с HTTP-соединениями без какого-нибудь обратного прокси-сервера перед сервером приложения. Например, Unicorn рекомендуется использовать только за обратным прокси-сервером, поскольку он не может буферизовать запросы, т.е. если клиент отправляет один байт запроса, а затем останавливается (из-за сетевых условий или плохого соединения сотовой связи), то процесс Unicorn прекращает работу и не продолжает до тех пор, пока запрос не завершит буферизацию. Использование NGINX перед Unicorn позволяет ему буферизовать запрос до того, как он достигнет Unicorn. Поскольку NGINX написан в высоко оптимизированном C и не ограничен GVL Ruby, он может буферизовать сотни соединений для Unicorn. Passenger решает эту проблему, будучи дополнением для NGINX или Apache( mod_ruby! ) и выгружая работы, связанные с подключением на веб-сервер.
По неизвестной причине «минимальное» количество процессов называется spare. В приведенном конфиге сразу запускается 5 процессов масштабируется до 10, если этого требует загрузка.
Пока ничего неизвестно о доступности таких настроек как Puma’s preload_app! и аналогов в Passenger и Unicorn, так что можете запускать процессы заранее и пользоваться преимуществом копирования при записи (cow memory).
Нам осталось обсудить процессы приложений. Что здесь есть интересного и нового? Маршрутизатор не взаимодействует с процессами приложений через HTTP — он использует сокеты Unix и разделяемую память. Эта оптимизация нацелена на микросервисную архитектуру, поскольку связь между сервисами на одной машине будет значительно быстрее без HTTP-прослойки. Однако я еще не видел примеры кода Ruby, где это реализовано.
Неясно, предназначено ли оно для запуска NGINX перед NGINX Unit и может ли NGINX Unit работать самостоятельно. Сейчас (1 квартал 2018 года) вы, вероятно, запускаете NGINX перед NGINX Unit в качестве обратного прокси-сервера, потому что NGINX Unit нет предоставления статических файлов, HTTPS (TLS) и HTTP / 2. Очевидно, это бесшовная интеграция.
NGINX Unit приближается к стабильной версии 1.0. Пока его рано запускать на продакшн для приложений Ruby. На момент написания статьи модулю Ruby исполнилось 5 дней. Он все еще на стадии активной разработки: новые версии выходят каждые несколько недель. На очереди крупные нововведения, связанные с TLS и HTTP, а там дело дойдет и до предоставления статических файлов. Идет дискуссия о поддержке Java, и как вариант — поддержке JRuby и TruffleRuby.
Поддержки Windows нет, и не то, чтобы я ждал ее, затаив дыхание. NGINX Unit поддерживает только Ruby 2.0 и выше.
Я не буду тестировать производительность NGINX Unit в этом посте. Модуль Ruby только появился, замерять производительность рано. Однако реальная причина, по которой я не буду сравнивать NGINX Unit с Puma, Unicorn или Passenger, заключается в том, что выбор сервера приложений в Ruby — это вопрос не скорости (технически — латентности), а пропускной способности. Мы различаем серверы приложений по количеству обслуживаемых запросов, а не по скорости обработки. Серверы приложений имеют латентность в считанные миллисекунды.
Важный параметр сервера приложений Ruby, который влияет на пропускную способность — многопоточность. Это единственный параметр сервера приложений, который увеличивает количество одновременных запросов. Многопоточный сервер приложений Ruby эффективнее использует ресурсы ЦП и памяти, и обслуживает больше запросов в минуту, чем однопоточный процесс приложения Ruby.
В настоящее время единственным бесплатным сервером приложений, который запускает веб-приложения Ruby в нескольких потоках, является Puma. В Passenger Enterprise нужно платить за лицензию.
NGINX Unit планирует поддержку нескольких потоков в приложениях Python, поэтому не исключено, что он будет поддерживать приложения Ruby в нескольких потоках в будущем.
Итак, где NGINX Unit сейчас уступает Unicorn, Passenger и Puma? Я думаю, при традиционной настройке Rails-приложений: одно монолитное приложение, работающее на провайдере платформа-как-сервис (например, Heroku), вообще не получит никакой пользы от текущих возможностей и запланированных нововведений NGNX Unit. Puma и так хороша для подобных задач.
NGINX Unit может быть интересен пользователям Unicorn, которые хотят отказаться от обратного прокси. Когда NGINX Unit будет отполирован, он заменит связку Unicorn / NGINX единственным сервером Unit NGNX.
NGINX Unit больше всего похож на Phusion Passenger, который перешел на «микросервисы», поддерживая Javascript, Python и приложения Ruby. NGINX Unit сейчас поддерживает больше языков и в будущем их число еще увеличится, поэтому на него переходят те, кому это важно. Зато Phusion сосредоточены на Ruby, поэтому Passenger всегда будет поддерживать Ruby лучше, полноценнее, чем NGINX Unit. Как я уже упоминал, Phusion Passenger Enterprise уже поддерживает многопоточность.
Где же NGINX Unit идеален? Если вы используете собственное облако (собственное, а не на сервисе, управляющем маршрутизацией, например Heroku), и у вас есть приложения Ruby, работающие на разных версиях языка, или много сервисов на разных языках, и эти сервисы/приложения нуждаются в быстром сообщении друг с другом, то NGINX Unit разработан для вас. В противном случае лучше придерживаться трех лучших вариантов (Puma, Passenger и Unicorn).
Сравнение php-fpm, nginx-unit и laravel-octane
Статья посвящена сравнению производительности различных веб-серверов для приложения, построенного на базе laravel. Ниже будет много графиков и параметров конфигурации и мои личные выводы, никак не претендующие на вселенскую истину.
О тестовом стенде
Характеристики тестового стенда:
CPU: AMD Ryzen 9 5900X 12-Core
RAM: DDR4 4000 MHz 32GiB x2
SSD: Samsung SSD 980 PRO 500GB nvme
Приложения для тестирования:
Облегченная версия Laravel, созданная в основном для реализации api-приложений. В части функциональности сохранил все самые важные компоненты Laravel, а то, что не является критически важным (например, фасады), урезано. При этом он более производителен чем Laravel, но далеко не все задачи на нем решать выгодно. Как это обычно бывает, для каждой конкретной задачи есть свой оптимальный инструмент. Для одних задач выгоднее использовать laravel, для других lumen, для третьих php использовать не выгодно вовсе.
Веб серверы:
Стандартный менеджер php процессов. Для каждого запроса требуется инициализация фреймворка.
Веб-сервер приложений, разработанный командой nginx. Для каждого запроса требуется инициализация фреймворка.
Версия php во всех сборках: 8.0.12
Инструменты для тестирования:
Yandex tank для проведения нагрузочного тестирования. Используется самый свежий из доступных docker-образ.
Telegraf (входит в набор инструментов yandex tank) для сбора статистики по используемым приложениями ресурсам компьютера.
Overload (так же из комплекта yandex tank) для построения графиков.
Конфигурация
Приложения
Все приложения имеют стандартную конфигурацию. Логирование ошибок отключено. Кэш собирается при первом обращении только для компонентов laravel/lumen (таких, как роутер и т.п.), для контроллеров кэша нет. У приложения 1 эндпоинт, который при обращении обрабатывает реквест, и возвращает встроенный json респонс, содержащий случайное число, параметр конфигурации, статическую строку и заголовки запроса. Пример ответа сервиса:
Все приложения поднимаются в docker-контейнерах. Во всех приложениях используется кастомный php.ini, со следующими параметрами:
Отдельные изменения, если таковые имеются, описаны для каждого приложения.
Для тестирования php-fpm используется дополнительный контейнер с nginx, поскольку php-fpm работает через протокол FastCGI. Используется официальный образ nginx:1.19.6-alpine.
Подопытные кролики, они же собранные контейнеры
1. nginx + php-fpm + laravel
Php-fpm: используется официальный образ php:8.0.12-fpm
Тут сразу стоит оговориться: изначально планировалось что каждому веб-серверу будет выделено 16 воркеров по числу логических ядер (об этом ниже), но с php-fpm возникли проблемы в процессе тестирования, пришлось выдавать ему больше воркеров.
2. nginx + php-fpm + lumen
Конфигурация полностью идентична «nginx + php-fpm + laravel»
3. nginx-unit + laravel
Так вышло, что немногим ранее я уже собирал контейнер с nginx-unit для php8, поскольку нормально работающих контейнеров, отвечающих моим производственным задачам не было. Не долго думая, именно этот контейнер я и использовал как основу, чуть доработав под текущее тестирование. Можно заметить, что сборка производилась на базе ubuntu:hirsute, поскольку с apline я не очень дружу, да и разбираться тогда времени с ним не было. Нужна была сборка здесь и сейчас, при этом не планировалось что она дойдет до прода в первозданном виде. Хотя, учитывая результаты тестов, теперь может и дойти.
4. nginx-unit + lumen
Конфигурация полностью идентична «nginx-unit + laravel»
5. laravel-octane (swoole) + laravel
Добавить к тестируемым приложениям octane меня побудило сообщение Тейлора (автора laravel) в твиттере. Меня смутили его утверждения «октан быстрее люмена» и «немного увеличить скорость». В связи с чем к тестам был добавлен наскоро собранный контейнер с laravel-octane, работающим на основе swoole.
Laravel-octane поддерживает помимо swoole еще и roadranner, и изначально я планировал протестировать и его. Но как ни странно, мне не удалось заставить работать последний нормально даже на костылях внутри докера (если быть точнее, удалось, но автодеплой он не переживал, только ручной старт), в связи с чем в последствие я от него отказался. Тем не менее, swoole мне было достаточно. Кроме того, Laravel-octane+swoole добавляют дополнительные инструменты, которые могут пригодиться при решении ряда стоящих передо мной задач.
Все остальные параметры передаются прямо в команде запуска сервера:
Yandex tank
Для тестирование было принято решение использовать 2 различных профиля нагрузки, отражающих 2 ситуации: «стандарт» для ежедневных часто встречающихся нагрузок, «стресс» для понимания границ работоспособности системы.
Профиль нагрузки «стандарт»
Идея теста в том, чтобы определить на что способен каждый конкретный веб-сервис и какое количество пользователей он способен выдержать стабильно и без сбоев. Профиль нагрузки:
Telegraf
С ним все просто, создана минимальная конфигурация для сбора данных о потребляемых ресурсах
Нагрузочное тестирование и результаты
Для тестирования все участники действия были жестко ограничены по количеству логических ядер процессора:
Контейнер с приложением: 16 ядер
Nginx (для тестов с php-fpm): 2 ядра
Yandex tank: 4 ядра (на 2 ядрах нехватало ресурсов для работы с php-fpm даже с уменьшенным таймаутом)
Чрезвычайно важный и крайне приоритетный процесс проталкивания /dev/zero в /dev/null (вопросы излишни, мой личный костыль, чтобы упростить себе жизнь): строго 1 полностью загруженное ядро
Все процессы ОС: оставшееся 1 ядро, фактически свободное, про запас
Все приложения тестировались с «холодным стартом», т.е. эндпоинт не подогревался, кэш не собирался до запуска теста.
График нагрузки на память не прикладывал, чтобы не увеличивать объем статьи до бесконечности. В синтетических тестах память почти не потребляется, и разница минимальна. Примерно по тем же соображениям у контейнеров не было ограничений по используемой памяти, благо ее хватает.
Профиль нагрузки «стандарт»
1. nginx + php-fpm + laravel
Время ответов сервера
Нагрузка на процессор
2. nginx + php-fpm + lumen
Время ответов сервера
Нагрузка на процессор
3. nginx-unit + laravel
Время ответов сервера
Нагрузка на процессор
4. nginx-unit + lumen
Время ответов сервера
Нагрузка на процессор
5. octane (swoole) + laravel
Время ответов сервера
Нагрузка на процессор
Перцентили времени ответа (ms)
nginx + php-fpm + laravel
nginx + php-fpm + lumen
octane (swoole) + laravel
Профиль нагрузки «стресс»
1. nginx + php-fpm + laravel
Время ответов сервера
Нагрузка на процессор
Сводка по ошибкам Детали тестирования этой сборки
Тестировать пришлось несколько раз. Первый раз, когда php-fpm было выделено 16 воркеров, а nginx имел настройки по умолчанию, вся эта сборка схлопнулась в черную дыру и на 120 rps начала орать об ошибках и недостаточном количестве воркеров (причем оба одновременно). После этого nginx был перенастроен на адекватную конфигурацию, а php было выделено 100 и 250 воркеров (2 теста, в итоге остановился на 100, для 250 не хватало логических ядер). Поскольку тестирование этим профилем нагрузки я проводил первым, в дальнейшем эта конфигурация и была использована на всех остальных тестах. Кроме того, я столкнулся с тем, что на отметке
120 rps php-fpm резко перестает справляться с нагрузками, запросы зависают, и yandex tank с дефолтным таймаутом запроса в 11 секунд начинает загибаться, ему банально не хватает ресурсов для обеспечения требуемого количества запросов. В связи с этим я выделил танку 4 ядра (изначально было 2), и снизил таймаут до 2 секунд. На графике хорошо видна эта 2-секундная отсечка, когда php-fpm загнулся. Но выводы будут ниже.
2. nginx + php-fpm + lumen
Время ответов сервера
Нагрузка на процессор
Сводка по ошибкам
3. nginx-unit + laravel
Время ответов сервера
Нагрузка на процессор
4. nginx-unit + lumen
Время ответов сервера
Нагрузка на процессор сводка по ошибкам
В процессе тестирования произошла 1 ошибка с http кодом 500 именно от самого приложения. В связи с отключенными логами, понять что именно случилось невозможно, и больше она не воспроизводилась при повторных прогонах. Однако, учитывая что на 300299 успешных запросов 1 оказался ошибочным, я посчитал что эту ошибку можно проигнорировать.
5. octane (swoole) + laravel
Время ответов сервера
Нагрузка на процессор
Сводка по ошибкам
Перцентили времени ответа (ms)
* Звездочкой в таблице будут отмечены сборки на базе php-fpm, которые не выдержали нагрузки вообще. У них будет указана отсечка rps, после которой они начали умирать. Как следствие, перцентили даны до этой отсечки. Я решил все же добавить их в таблицу, хотя бы в таком виде.
* nginx + php-fpm + laravel
* nginx + php-fpm + lumen
octane (swoole) + laravel
* octane (swoole) + laravel
Выводы
Итоги тестирования меня, надо признать, удивили. Я конечно ожидал, что php-fpm будет медленнее чем, nginx-unit, но не настолько: разница во времени генерации ответа почти в 10 раз. Так же меня удивило то, что php-fpm оказался единственным, который под стресс тестом захлебнулся вообще. Возможно, это связано с тем, что я не являюсь экспертом в конфигурации nginx и php, но остальные сервера, работавшие на том же конфиге, стресс тест выдержали, хоть и с потерями. В итоге, я пришел к выводу, что я не зря давно уже пересел на nginx-unit.
Что касается сравнения производительности: если не брать в расчет php-fpm, то nginx-unit единственный, кто выдержал стресс тест без потерь, хотя на octane я возлагал большие надежды. В связи с этим, php-fpm я дальше учитывать в своих рассуждениях не буду.
Скачки времени выполнения для 100% перцентиля наблюдаются и у nginx-unit и у octane+swoole, но в обоих случаях не сказать, чтобы они были катастрофическими, а причины их могут быть вовсе в том, что все тестирование произодилось на «слегка» не предназначенном для этого железе и окружении. Опять же, все тесты были сугубо синтетическими, и в реальных условиях, когда приложение будет помимо всего прочего и бизнес логику ворочать, и в базу и кэш ходить, ситуация будет иная.
С другой стороны, nginx-unit оказался более стабилен при высоких нагрузках. И при этом в синтетических тестах в связке с lumen почти не проигрывает octane, так что я не зря сомневался в словах Тейлора. Lumen еще поживет и продолжит удивлять (во всяком случае меня, я не ожидал от него такой прыти по сравнению с laravel).
Надеюсь, статья кому-либо поможет выбрать инструмент для решения своих задач.