Производительность Apache и Nginx: методы оптимизации

Apache был выпущен в 1995 году, и, согласно Википедии, «сыграл ключевую роль в развитии Всемирной паутины». На сегодняшний день это все ещё наиболее часто используемое программное обеспечение для работы серверов. Но наблюдается тенденция снижения доли рынка Apache и роста Nginx.

Nginx был выпущен в 2004 году. Сначала он использовался в виде дополнения к Apache. Но его популярность неуклонно растет.

Apache существует давно, и для него доступен большой набор модулей. Известно, что управление серверами Apache удобно для посетителя. Динамическая загрузка модулей может компилировать и добавлять разные модули в стек Apache без перекомпиляции двоичного файла главного сервера.

Подобная гибкость ещё не доступна для Nginx. Из руководства по параметру Nginx для HTTP/2 становится ясно, что его модули настраиваются во время сборки.

Ещё одна особенность, которая обеспечила Apache доминирование на рынке веб-серверов, это файл.htaccess. Он может контролировать конфигурацию сервера на уровне каталогов. Каждый каталог на сервере, обслуживаемом Apache, может иметь собственный файл.htaccess.

Nginx не только не имеет в себя эквивалентного решения, но и препятствует его внедрению из-за снижения производительности.

Производительность Apache и Nginx: способы оптимизации

Доли рынка для разных серверов в 1995–2005 гг.

LiteSpeed — это один из претендентов, который можно сравнить с Apache. Но он лишен проблем с производительностью.

Как и Apache он поддерживает.htaccess, mod_security и mod_rewrite. LiteSpeed был задуман как замена Apache. Он работает с cPanel и Plesk, с 2015 года поддерживает HTTP/2.

Это делает LiteSpeed серьезным конкурентом, ориентированным на хостинг-провайдеров, уделяющих внимание производительности. Но он также может использоваться для небольших серверов или веб-сайтов.

Вопросы аппаратного обеспечения

Какое бы из данных решений мы ни выбрали, наличие достаточного объема ОЗУ имеет в себя большое значение. Когда процесс веб-сервера не имеет в себя достаточного объема оперативной памяти, он начинает использовать файл подкачку. Он подразумевает использование жесткого диска или SSD для расширения оперативной памяти. В результате увеличивается время ожидания при каждом обращении к данной памяти.

Мониторинг

Htop будет одним из эффективных методов мониторинга текущей производительности стека серверов.

Производительность Apache и Nginx: способы оптимизации

Иные инструменты мониторинга: New Relic, Netdata. Последнее решение может отправлять предупреждения для любого приложения или системного процесса по электронной почте, через Slack, pushbullet, Telegram, Twilio и т. д.

Производительность Apache и Nginx: способы оптимизации

Monit — ещё один инструмент с открытым исходным кодом, который может контролировать систему. В нем можно изменить отправку оповещений, перезапуск определенных процессов или перезагрузку системы при выполнении заданных условий.

Тестирование системы

AB(Apache Benchmark) — простой инструмент тестирования нагрузки от Apache Foundation. Ещё одна программа для тестирования — Siege. Также доступен инструмент на основе Python — Locust.

Производительность Apache и Nginx: способы оптимизации

После установки Locust необходимо будет создать файл locust в каталоге, из которого вы запускаете приложение:

from locust import HttpLocust, TaskSet, taskclass UserBehavior(TaskSet): @task(1) def index(self): self.client.get("/") @task(2) def shop(self): self.client.get("/?page_id=5")  @task(3)    def page(self):        self.client.get("/?page_id=2")class WebsiteUser(HttpLocust):    task_set = UserBehavior min_wait = 300 max_wait = 3000

Далее запускаем инструмент из командной строки:

locust --host=https://my-website.com

Применение перечисленных выше средств создает эффект DDoS-атаки, так что рекомендуется ограничить тестирование собственными веб-сайтами.

Параметр Apache

MPM-модули Apache

Вначале существования Apache создавал новый процесс для каждого входящего TCP-соединения и ответа на него. Если появлялись иные соединения, создавались иные рабочие процессы для их обработки.

Чтобы снизить затраты ресурсов, разработчики Apache создали режим prefork с заранее заданным числом процессов. Но встроенные динамические языковые интерпретаторы в каждом процессе все равно потребляли много ресурсов, Так что сбои в работе серверов Apache с параметрами по умолчанию стали распространенным явлением.

Эта модель известна как mpm_prefork_module. Данный режим требует небольшой параметра. При этом значение, задаваемое директивой MaxRequestWorkers, должно быть достаточно большим, чтобы обрабатывать столько одновременных запросов, сколько вы ожидаете приобрести. Но достаточно малым, чтобы обеспечить необходимый объем физической памяти для всех процессов.

Производительность Apache и Nginx: способы оптимизации

Тест Locust, который показывает порождение огромного числа процессов Apache для обработки входящего трафика.

Этот режим будет основной причиной плохой репутации Apache. Его использование может привести к неэффективному распределению ресурсов.

Версия Apache 2 реализовала ещё два MPM, которые пытались решить проблемы, связанные с режимом prefork. Это модуль worker(mpm_worker_module) и модуль событий.

Модуль worker реализует гибридный режим работы, основанный на потоке процессов. Согласно официальному веб-сайту Apache:

Родительский процесс управления отвечает за запуск дочерних процессов. Каждый из них создает фиксированное число потоков, указанное в директиве ThreadsPerChild. А также поток, который прослушивает соединения и передает их потоку сервера для обработки, когда они поступают.

Этот режим использует ресурсы более эффективно.

В версии Apache 2.4 появился модуль событий. Он добавляет отдельный поток прослушивателя, который управляет бездействующими соединениями после завершения HTTP-запроса. Это неблокирующий асинхронный режим, потребляющий меньший объем памяти.

Мы загрузили тестовую установку WooCommerce с 1200 записями на виртуальном сервере и протестировали ее на Apache 2.4 со стандартным режимом, prefork и mod_php.

Сначала мы протестировали его в libapache2-mod-php7 и mpm_prefork_module на https://tools.pingdom.com:

Производительность Apache и Nginx: способы оптимизации

Далее мы провели тестирование MPM модуля событий. Нам необходимо было добавить multiverse в /etc/apt/sources.list:

deb http://archive.ubuntu.com/ubuntu xenial main restricted universe multiversedeb http://archive.ubuntu.com/ubuntu xenial-updates main restricted universe multiversedeb http://security.ubuntu.com/ubuntu xenial-security main restricted universe multiversedeb http://archive.canonical.com/ubuntu xenial partner

После этого мы выполнили sudo apt-get update и установили libapache2-mod-fastcgiphp-fpm:

sudo apt-get install libapache2-mod-fastcgi php7.0-fpm

Так как php-fpm — это служба, отдельная от Apache, требуется выполнить ее перезапуск:

sudo service start php7.0-fpm

Далее мы отключили модуль prefork, включили режим событий и proxy_fcgi:

sudo a2dismod php7.0 mpm_preforksudo a2enmod mpm_event proxy_fcgi

После чего добавили следующий фрагмент кода к виртуальному хосту Apache:

<filesmatch ".php$">    SetHandler "proxy:fcgi://127.0.0.1:9000/"</filesmatch>

Указанный порт должен соответствовать конфигурации php-fpm в /etc/php/7.0/fpm/pool.d/www.conf. Более подробно о параметру php-fpm можно легко узнать здесь.

Далее мы настроили конфигурацию mpm_event /etc/apache2/mods-available/mpm_event.conf. Подробнее о каждой директиве для веб-сайта на Apache и

Директива MaxRequestWorkers устанавливает ограничение на число одновременных запросов. Значение, не равное нулю, предотвращает возможную утечку памяти.

<ifmodule mpm_event_module>        StartServers 1 MinSpareThreads 30 MaxSpareThreads 75 ThreadLimit 64 ThreadsPerChild 30 MaxRequestWorkers 80 MaxConnectionsPerChild 80</ifmodule>

Далее мы перезапустили сервер при помощи sudo service apache2 restart. Тестирование на Pingdom показало, что время загрузки страницы сократилось вдвое:

Производительность Apache и Nginx: способы оптимизации

Иные советы по параметру Apache:

Отключение.htaccess: Этот файл может создать конфигурацию для каждого отдельного каталога в корне сервера без перезагрузки. Таким образом, обход всех каталогов, поиск файлов.htaccess при каждом запросе влечет за собой снижение производительности.

Выдержка из документации Apache:

Файлы .htaccess следует использовать только в том случае, если у вас нет доступа к основному файлу конфигурации сервера. Любые параметра конфигурации .htaccess, могут быть также выполнены в разделе <directory> файла конфигурации основного сервера.

Решение заключается в том, чтобы отключить этот файл в /etc/apache2/apache2.conf:

AllowOverride None

Если необходимо использовать.htaccess для конкретных каталогов, можно легко включить его в разделы виртуального хоста:

AllowOverride All

Дополнительные советы:

  • Управляйте кешем браузера при помощи mod_expires — устанавливая заголовки expires.
  • Оставьте HostNameLookups выключенным — HostNameLookups Off,это значение, используемое по умолчанию.
  • Apache2buddy — скрипт, который можно без труда запустить и приобрести советы по параметру системы:
curl -sL https://raw.githubusercontent.com/richardforth/apache2buddy/master/apache2buddy.pl | perl
Производительность Apache и Nginx: способы оптимизации

Nginx

Это сервер, работающий на основе событий. Переход на Nginx часто будет решением многих проблем с производительностью веб-сайта или сервера.

Производительность Apache и Nginx: способы оптимизации

Более подробное визуальное пояснение архитектуры Nginx можно легко найти здесь.

Параметра Nginx

Nginx рекомендует привязывать число потоков workers к числу ядер процессора, установив в /etc/nginx/nginx.conf для worker_processes значение auto (по умолчанию используется значение 1).

worker_connections устанавливает число соединений, которые может обработать каждый процесс worker . По умолчанию — 512, но это значение можно легко увеличить.

Keepalive-соединения также влияет на производительность.

Производительность Apache и Nginx: способы оптимизации

Согласно официальному веб-сайту Nginx :

HTTP keepalive-соединения — это необходимая функцию производительности, которая снижает задержку и может быстрее загружать веб-страницы.

Установление новых TCP-соединений может быть ресурсоемким. Протокол HTTP/2 частично решает эту проблему благодаря возможностям мультиплексирования . Повторное использование существующего соединения может сократить время обработки запроса.

Workers Nginx могут обрабатывать тысячи входящих соединений одновременно. Если Nginx применяется в виде обратного прокси-сервера, то он использует локальный пул keepalive-соединений без издержек TCP-соединения.

Настройка keepalive_requests устанавливает число запросов, которые покупатель может выполнить через одно keepalive-соединение. Настройка keepalive_timeout устанавливает время, в течение которого keepalive- соединение остается открытым.

Включение входящих keepalive-соединений требует помещения данных директив в основную конфигурацию Nginx:

proxy_http_version 1.1;proxy_set_header Connection "";

Они управляются модулем ngx_http_upstream_module .

Если интерфейсное приложение продолжает опрашивать фоновое приложение о наличии обновлений, увеличение значений keepalive_requests и keepalive_timeout ограничит число соединений, которые надо установить.

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

Использование unix сокетов

По умолчанию Nginx использует отдельный процесс PHP, в который он перенаправляет запросы PHP-файлов. В этом он действует как прокси.

Установка виртуального хоста с Nginx будет выглядеть так:

location ~ .php$ {    fastcgi_param REQUEST_METHOD $request_method;    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;    fastcgi_pass 127.0.0.1:9000;}

FastCGI — это протокол, отличный от HTTP. Так что первые две строки передают аргументы и заголовки в php-fpm. Третья строка указывает метод проксирования запроса — через сокет локальной сети.

Это удобно для многосерверных установок, так как мы можем указать удаленные серверы для проксирования запросов.

Но если мы размещаем всю установку в одной системе, необходимо использовать Unix сокет для подключения к процессу прослушивания php:

fastcgi_pass unix:/var/run/php7.0-fpm.sock;

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

Nginx предлагает директиву gzip_static , которая может обслуживать сжатые версии файлов с расширением .gz вместо обычных ресурсов:

location /assets {    gzip_static on;}

Таким образом, Nginx будет пытаться обслуживать style.css.gz вместо style.css . Так что мощности ЦП не будут тратиться на сжатие «на лету» для каждого запроса.

Кеширование при помощи Nginx

Включить кеширование в Nginx довольно просто.

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m;

Эту директиву мы помещаем в файл виртуального хоста, вне блока server . Аргумент proxy_cache_path может быть любым путем, по которому сохраняется кэш.

levels определяет число уровней каталогов, в которых Nginx должен хранить кэшированное содержимое.

Аргумент keys_zone — это имя общей зоны памяти, используемой для хранения ключей кэша. 10m - это объем памяти, выделяемый для данных ключей.

max_size не будет обязательным настройкою и устанавливает верхний предел для размера кэшируемого содержимого. В нашем случае это 10 ГБ.

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

После этого также следует указать строку с именем зоны памяти либо в блоке server или в блоке location :

proxy_cache my_cache;

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

proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;

Более подробную информацию о директивах блоков server и location для Nginx можно найти здесь .

Директивы proxy_cache_* предназначены для статических ресурсов. Но чаще необходимо кэшировать динамический отображение веб-приложений. В этом случае мы будем использовать следующую директиву:

fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=my_cache:10m inactive=60m; fastcgi_cache_key "$scheme$request_method$host$request_uri"; fastcgi_cache_use_stale error timeout invalid_header http_500; fastcgi_ignore_headers Cache-Control Expires Set-Cookie; add_header NGINX_FASTCGI_CACHE $upstream_cache_status;

Последняя строка устанавливает заголовки ответа, чтобы сообщить нам, был ли контент доставлен из кэша или нет.

Далее в блоке server или location можно установить исключения для кэширования. К примеру, если строка запроса присутствует в URL-адресе:

if ($query_string != "") {    set $skip_cache 1;}

Также в блоке server при использовании PHP мы добавляем следующий программный код:

location ~ .php$ {    try_files $uri =404;    include fastcgi_params;    fastcgi_read_timeout 360s;    fastcgi_buffer_size 128k;    fastcgi_buffers 4 256k;    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;    fastcgi_pass unix:/run/php/php7.0-fpm.sock;      fastcgi_index index.php;      fastcgi_cache_bypass $skip_cache;      fastcgi_no_cache $skip_cache;      fastcgi_cache my_cache;      fastcgi_cache_valid 60m;}

Строки fastcgi_cache* и fastcgi_no_cache настраивают кэширование и исключения. Подробное описание данных директив можно легко найти в документации Nginx .

Заключение

Мы рассмотрели пару способов улучшения производительности веб-сервера. Достижение наилучших результатов в Apache и Nginx осуществляется путем тестирования и анализа конкретных случаев. Так что это бесконечная тема.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *