Настройка apache MPM (prefork, worker, event)

 Posted on June 25, 2017 at 12:48 a.m.

Статья про apache MPM prefork, worker, event, примеры конфигураций

Apache (он же httpd) - один из самых популярных веб-серверов, который может работать на множестве платформ. Различные окружения и платформы могут реализовывать один и тот же функционал по разному, поэтому не существует идеального рецепта конфигурации, в каждом случае требуется индивидуальный подход. Правильная настройка сервиса сделает пользователей счастливыми, а админа спокойным.

Про отключение неиспользуемых модулей слышали пожалуй все, а сегодня мы поговорим про MPM (Multi-Processing Modules) - prefork, worker и event.

Содержание:

Intro

Apache имеет модульную архитектуру, что позволяет выбрать необходимую функциональность, которая будет реализована при помощи подключаемых модулей. В Apache 2.0 модульная архитектура была расширена наиболее общими функциями веб-сервера. Теперь сервер поставляется с набором мульти-процессных модулей (MPM), ответственных за сетевое соединение, за прием запросов и за координацию их обработки дочерними процессами.

Для Unix систем для определения какой-же модуль можно использовать можно воспользоваться таблицей:

В системе есть поддержкаeventworkerprefork
threads++-
thread-safe polling (kqueue и epoll)+--

Фактически это означает, что для Unix почти всегда будет доступен event, так как все современные операционные системы поддерживают эти две функции. *PHP по умолчанию не поддерживает thread safe, поэтому если вам нужен mod_php - используйте prefork.

Для проверки какой модуль используется в данным момент можно использовать команды:

httpd -M |grep mpm
или
httpd -V | grep -i mpm

По умолчанию в Apache 2.4 подключен модуль prefork.

Prefork

При использовании модуля prefork каждый запрос обслуживается отдельным процессом Apache. Основное преимущество prefork - стабильность, процессы изолированы друг от друга и ошибки при обработке одного запроса ни как не затронут другие запросы. Родительский процесс отвечает за запуск дочерних процессов, которые обслуживают соединения. Apache старается всегда держать в резерве несколько процессов (обычно их называют spare или idle процессы) для того чтобы клиенты не ждали пока запустится дочерний процесс для обслуживания их запроса.

Одна из важнейших директив для настройки этого MPM - MaxRequestWorkers (или MaxClients для версий ниже 2.3.13). Фактически она определяет максимальное количество одновременно обслуживаемых клиентов и соответственно от этой директивы зависит максимальное потребление RAM.

Пример конфигурационного файла (Apache/2.2.15 Centos 6)

<IfModule prefork.c>
StartServers       8
MinSpareServers    5
MaxSpareServers   20
ServerLimit      256
MaxClients       256
MaxRequestsPerChild  4000
</IfModule>

StartServers: число процессов, которые запустятся при старте Apache.
MinSpareServers: минимальное количество процессов, которые держатся в резерве.
MaxSpareServers: максимальное количество процессов, которые держатся в резерве.
ServerLimit: максимальное количество процессов Apache (в целом).
MaxClients: максимальное число одновременных клиентских соединений (в разрезе prefork = максимальному количеству дочерних процессов).
MaxRequestsPerChild: максимальное количество запросов, после которых дочерний процесс будет перезапущен (позволяет нивелировать эффект от memory leak).

Для базовой настройки необходимо поменять только MaxClients (MaxRequestWorkers) и ServerLimit, остальные параметры на первом этапе можно оставить по умолчанию.

Расчет MaxClients (MaxRequestWorkers)

Допустим нам необходимо выделить 512Mb для Apache. Для этого выясняем сколько RAM потребляет один процесс Apache (только по одному этому пункту можно написать отдельную книгу, но для начала нам хватит метода описанного далее): запускаем ps и выясняем pid дочернего процесса (родительский будет запущен от пользователя root), далее запускаем pmap и смотрим параметр writeable/private, в примере это 1776K (1.7Mb).

$sudo ps aux |grep httpd
root     10132  0.4  0.4 221936  4980 ?        Ss   07:22   0:00 /usr/sbin/httpd -DFOREGROUND
apache   10133  0.0  0.2 221936  2952 ?        S    07:22   0:00 /usr/sbin/httpd -DFOREGROUND
apache   10134  0.0  0.2 221936  2952 ?        S    07:22   0:00 /usr/sbin/httpd -DFOREGROUND
apache   10135  0.0  0.2 221936  2952 ?        S    07:22   0:00 /usr/sbin/httpd -DFOREGROUND

$sudo pmap -d 10133 | tail -1
mapped: 221936K    writeable/private: 1776K    shared: 76K

Дальше все просто: 512/1.7 = 301 - вот значение для ServerLimit и MaxClients (MaxRequestWorkers). В реальности будут другие цифры, в примере использовался свежеустановленный Apache без нагрузки и без mod_php, и лучше брать среднее значение от потребления RAM всеми дочерними процессами, а не значение одного случайного процесса и проводить замеры во время наибольшей нагрузки или во время нагрузочного тестирования. Если вы еще не знаете какая будет нагрузка и сколько будет потреблять RAM один процесс, то ориентируйтесь на цифру в 25Mb - 35Mb (если планируете использовать mod_php), для начала этого хватит, позже вернетесь к этому параметру.

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

$sudo ps aux | grep httpd | wc -l

Worker

Worker сочетает в себе мульти-процессовый (multi-process) и мульти-поточный (multi-threaded) сервер. Использование потоков (threads) позволяет обслуживать больше запросов при меньших аппаратных ресурсах чем просто мульти-процессовый сервер (prefork). Тем не менее, он сохраняет большую часть стабильности мульти-процессового сервера, используя несколько процессов, каждый из которых имеет множество потоков.

Как это работает:
- родительский процесс отвечает за запуск дочерних процессов;
- каждый дочерний процесс создает фиксированное количество потоков, установленных директивой ThreadsPerChild и один слушающий поток (listener thread), который принимает новые соединения и передает их рабочим потокам;
- Apache постоянно пытается поддерживать пулл резервных потоков, которые готовы обслужить входящие запросы, как только они поступят. В этом случае клиенту не придется ждать создания нового потока или процесса.

Пример конфигурационного файла (Apache/2.2.15 Centos 6)

<IfModule worker.c>
StartServers         4
MaxClients         300
MinSpareThreads     25
MaxSpareThreads     75
ThreadsPerChild     25
MaxRequestsPerChild  0
</IfModule>

StartServers: число процессов, которые запустятся при старте Apache.
MaxClients: максимальное число одновременных клиентских соединений (в разрезе worker = максимальному количеству потоков).
MinSpareThreads: минимальное количество потоков, которые держатся в резерве.
MaxSpareThreads: максимальное количество потоков, которые держатся в резерве.
ThreadsPerChild: количество потоков на один процесс.
MaxRequestsPerChild: максимальное количество запросов, после которых дочерний процесс будет перезапущен (позволяет нивелировать эффект от memory leak).
ThreadLimit: максимальное число потоков для одного процесса (не может быть изменена без перезапуска сервера apache, в отличии от ThreadsPerChild)

Может возникнуть ситуация, при которой процесс достигший MaxRequestsPerChild будет ожидать завершения и перестанет принимать новые соединения, но у него будет один поток, который все еще обрабатывает клиентское соединение. Так мы можем достигнуть порог MaxClients (MaxRequestWorkers), хотя фактически клиентских запросов обрабатывается гораздо меньше. Чтобы избежать такого поведения сервера можно установить MaxRequestsPerChild в 0 и MaxSpareThreads = MaxClients (MaxRequestWorkers).

Расчет ServerLimit и MaxClients (MaxRequestWorkers)

Схема остается прежней, смотрим потребление RAM одним процессом, рассчитываем ServerLimit. MaxClients (MaxRequestWorkers) рассчитываем как ServerLimit * ThreadsPerChild.

Event

Event позволяет обслуживать большое количество одновременных соединений путем передачи части работы по обработке запроса отдельным потокам (listeners threads).

Этот MPM призван исправить проблему "keep alive" в HTTP. После того, как клиент выполнит первый запрос, он может оставить соединение открытым, отправляя будущие запросы используя тот же самый сокет избегая накладных расходов при установлении нового TCP-соединения. В случае prefork и worker Apache сохраняет дочерний процесс / поток, ожидающий данных от клиента, что приводит к неэффективному расходу ресурсов. Чтобы решить эту проблему, event использует выделенный поток (listener thread) для каждого процесса для обработки сокетов в состоянии Listening, Keep Alive и сокетов, для которых осталось только передать данные клиенту. Таким образом рабочий поток получает уже готовый запрос и освобождается сразу после его обработки.

Директивы остаются такими же как и у MPM worker, принцип расчета RAM остается тот же.

Выводы

  • Если вы используете связку apache+php (mod_fcgid, mod_fastcgi, mod_proxy_fcgi), то стоит обратить внимание на worker или event.
  • Если у вас старая самописная CMS или вы используете mod_php - то для вас, prefork, вероятнее всего, будет единственным доступным вариантом.
  • Не копируйте настройки с интернета, рассчитывайте параметры под свою систему, после конфигурации проводите тестирование.