Оптимизация конфигурации Apache prefork MPM работающего как backend под frontend-ом Nginx + mod_rpaf

archive view archive save

Оптимизация конфигурации Apache prefork MPM работающего как backend под frontend-ом Nginx Проблема родителей и детей существовала всегда и не только в семье Apache prefork MPM работающего как backend под frontend-ом Nginx, а и в обычных традиционных человеческих семьях, где бесконтрольно расплодившиеся child-ы (дети) пожирали одним махом всё шо было нажито непосильным трудом!:)

Например мы, Apache prefork MPM, живём вчетвером (httpd) на десяти сотках земли (мегабайтах памяти) и нам этого вполне хватает для нормальной жизни на протяжении 365-и дней в году, обычно рождая одного child-а (потомка) раз в 10-30 лет (сек.) и отпевая за этот же период по одному потомку (httpd). Такая схема жизни позволяет жить тихо мирно и без скандала, поддерживать связь с окружающим миром, frontend-ом Nginx, находить время для отдыха и творчества.

Но вдруг мы всей семьёй Apache prefork MPM сходим с ума и начинаем бесконтрольно плодить child-ов (детей httpd) так, как будто мы живём не на десяти сотках (мегабайтах памяти) земли, а на 10-ти гектарах (гигабайтах памяти), а у тех child-ов в свою очередь тоже съезжает чердак и они начинают плодится без остановки. Семья Apache prefork MPM живущая как backend под frontend-ом Nginx начинает голодать обслуживая своих многочисленно порождённых child-ов, которые заполонив отведённые нам 10-ть соток стали брать кредиты в банках под большие проценты, искать свободные территории (ушли в Swap) и воевать с соседями (сервисами) за ресурсы (память, ЦП и т.д.).

В итоге сошедшая с ума семья Apache prefork MPM со своими расплодившимися child-ами стала очень редко и туго контачить с окружающим frontend-ом Nginx, перестала отдыхать и заниматься творчеством - настал типа кризис:) Для того чтобы поправить ситуацию в семье Apache prefork MPM, нам нужно либо реже плодить child-ов, дожидаясь пока позаворачиваются уже наделанные или убивать их раньше времени сократив их срок жизни.:)

Ну, третьего тут не дано - или в семье Apache prefork MPM не плодить child-ов сверх необходимого или же убивать их раньше времени, а в некоторых случаях будет полезно и то и другое! Госпади, какие кошмарные планы, убивать child-ов это же не гуманно!;)) Гуманно или не гуманно, а всё равно места на всех child-ов Apache prefork MPM не хватит!

Итак, да прасти нас Госпади, приступим к осуществлению геноцида child-ов рода Apache prefork MPM:) После рестарта/перезапуска веб сервера Apache запускаем утилиту topи смотрим в Mem: ... 105129k free, ..., т.е. после рестарта/перезапуска веб сервера Apache у нас было больше 100 МВ (105129k) свободного оперативного мозга/памяти, а через 10-30 мин. работы, веб сервер Apache с настройками по умолчанию, снова вместе со своими расплодившимися child-ами (детьми) съел всю раму (RAM) надолго и не подавился. В результате получили вечное Mem: ... 4083k free, ..., а всё остальное уйдёт в Swap брать кредиты под большие проценты!:)

Потому как Apache prefork MPM работает у нас как backend под frontend-ом Nginx-а, то KeepAlive Off, Timeout 10 вместо 60-ти, а также пониженные значения параметров Apache prefork MPM, в скобках указаны значения по умолчанию:

Timeout 10
KeepAlive Off
KeepAliveTimeout 2
 
# prefork MPM
# StartServers: number of server processes to start (8)
# MinSpareServers: minimum number of server processes which are kept spare (5)
# MaxSpareServers: maximum number of server processes which are kept spare (20)
# ServerLimit: maximum value for MaxClients for the lifetime of the server (256)
# MaxClients: maximum number of server processes allowed to start (256)
# MaxRequestsPerChild: maximum number of requests a server process serves (4000)
<IfModule prefork.c>
    # количество детей создаваемых при запуске Apache
    StartServers 3
    # минимальное число неиспользуемых (ждущих) дочерних процессов сервера
    MinSpareServers 3
    # максимальное число неиспользуемых (ждущих) дочерних процессов сервера
    MaxSpareServers 7
    # максимальное количество одновременных соединений
    ServerLimit 64
    MaxClients 64
    # child-ы после обработки 300-т запросов к нему масцдай
    MaxRequestsPerChild 300
</IfModule>
  • StartServers - количество детей создаваемых при запуске Apache
  • MinSpareServers - минимальное число неиспользуемых (ждущих) дочерних процессов сервера
  • MaxSpareServers - максимальное число неиспользуемых (ждущих) дочерних процессов сервера
  • ServerLimit (MaxClients) - максимальное количество одновременных соединений
  • MaxRequestsPerChild - child-ы, после обработки этого количества запросов к ним, масцдай

Если мозг продолжает утекать, то можно попробовать понизить MaxRequestsPerChild до 100-150 или испробовать такую комбинацию:

Timeout 5
KeepAlive Off
KeepAliveTimeout 2
 
# prefork MPM
# StartServers: number of server processes to start (8)
# MinSpareServers: minimum number of server processes which are kept spare (5)
# MaxSpareServers: maximum number of server processes which are kept spare (20)
# ServerLimit: maximum value for MaxClients for the lifetime of the server (256)
# MaxClients: maximum number of server processes allowed to start (256)
# MaxRequestsPerChild: maximum number of requests a server process serves (4000)
<IfModule prefork.c>
    StartServers 3
    MinSpareServers 3
    MaxSpareServers 4
    ServerLimit 24
    MaxClients 24
    MaxRequestsPerChild 250
</IfModule>

Теперь после перезапуска/рестарта Apache service httpd restartкругооборот child-ов рода Apache prefork MPM работающего как backend под frontend-ом Nginx существенно стабилизировался и пожираемая ими память составляет в пределах 20-90 МВ, оставляя нам в Mem: ... 10388k free, ..., с частым регулярным освобождением памяти до Mem: ... 55278k free, ..., и выше до 80 МВ.

При таких настройках Apache prefork MPM работающего как backend под frontend-ом NginxMem: ... 10388k-18238k free держится стабильно даже при одновременном натиске Googlebot/2.1 и других пользователей, а когда сайтеги сервера перестают непрерывно юзатся то памяти освобождается до 80 МВ!

Так у нас теперь в семье Apache prefork MPM установился нормальный баланс чилдов, нахлобучивание которых ограничено параметрами MaxSpareServers, ServerLimit и MaxClients, а MaxRequestsPerChild заставляет child-ов самоубиваться после обработки 300-т запросов.

Значение параметра MaxRequestsPerChild можно установить с запасом, в два три раза превышающее значение поля Requests (количество запросов для загрузки страницы) в результатах анализа скорости загрузки сайта, хотя тут ещё играют роль значения директив MaxSpareServers, ServerLimit и MaxClients и чем меньше (child-ов) их значение, то тем больше можно увеличить (время их жизни) значение для MaxRequestsPerChild.

Такая конфигурация Apache prefork MPM работающего как backend под frontend-ом Nginx хорошо подходит для серверов с размером оперативной памяти в 256 МВ, где 120-140 уходит под работу системы, а 100-110 остаётся в свободном распоряжении.

Недостатки Apache prefork MPM backend под frontend-ом Nginx

Одним из пока найденных недостатков является невозможность правильного определения CMS-ами внешнего ИП пришедшего пользователя, который будет определятся как 127.0.0.1/localhost, адрес frontend-а Nginx берущего контент с backend Apache prefork MPM!

В этом можно убедится посетив главную страницу нашего сайта, смотреть внизу страницы на "Внешний IP" и "Прокси сервер", где в "Прокси сервер" будет указан ваш реальный ИП но, увы, теряется возможность определения наличия реального прокси сервера, который возможно будет использовать посетитель!

Решается установкой mod_rpaf на Apache (reverse proxy add forward module for Apache) или mod_realip2 (mod_realip для Apache 1.3). Устанавливаем mod_rpaf:

wget http://centos.alt.ru/repository/centos/6/i386/centalt-release-6-1.noarch.rpm
rpm -Uvh centalt-release*rpm
yum install mod_rpaf

Модули у нас валяются в /etc/httpd/modules -> /usr/lib64/httpd/modules, дополнительные конфиги в httpd.confгрузятся директивойInclude conf.d/*.confиз /etc/httpd/conf.d, делаем конфиг для mod_rpaf:

vi /etc/httpd/conf.d/mod_rpaf.conf
 
LoadModule rpaf_module modules/mod_rpaf-2.0.so
 
RPAFenable On
RPAFsethostname On
RPAFproxy_ips 127.0.0.1
RPAFheader X-Forwarded-For
 
service httpd restart

ВНИМАНИЕ! В mod_rpaf.conf директиву RPAFsethostname On лучше закомментировать иначе при работе с формами авторизации и пр. может косячить на внешний IP зашедшего пользователя!

Проблемы: mod_rpaf не работает

Для правильной работы модуля mod_rpaf под Apache в связке с Nginx, веб сервер Nginx должен быть скомпилирован с поддержкой модуля ngx_http_realip_module, поддержка которого обеспечивается с помощью конфигурационного параметра --with-http_realip_module, который согласно официальной документации по умолчанию опускается (не собирается) во время компиляции Nginx но, в тоже время, обычно сборки Nginx доступные в большинстве репозиториев скомпилированы с конфигурационным параметром --with-http_realip_module. Проверить скопмилирован ли ваш Nginx с конфигурационным параметром --with-http_realip_module можно выполнив nginx -V - если в результатах присутствует --with-http_realip_module, то значит с ngx_http_realip_module всё ОК.

Мало того, недостаточно одного наличия скомпилированных и подключённых модулей ngx_http_realip_module и mod_rpaf, для передачи реального IP с Nginx в Apache нужно правильно настроить, передать и принять HTTP заголовки:

[root@localhost ~]# vi /etc/httpd/conf.d/mod_rpaf.conf
 
.....
RPAFheader X-Real-IP
RPAFheader X-Forwarded-For
 
[root@localhost ~]# service httpd restart
[root@localhost ~]# vi /etc/nginx/nginx.conf
 
server {
    location /
    {
        .....
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $http_x_forwarded_for;
    }
}
[root@localhost ~]# service nginx restart

Пробремы с mod_rpaf после обновления до mod_rpaf-0.8-3.el6.art.x86_64.rpm

После обновления mod_rpaf-0.6-2.el6.art.x86_64.rpm до mod_rpaf-0.8-3.el6.art.x86_64.rpm, при старте Apache выдает такие ошибки:

[root@localhost ~]# httpd -t
Syntax error on line 222 of /etc/httpd/conf/httpd.conf: Syntax error on l
ine 2 of /etc/httpd/conf.d/mod_rpaf.conf: Cannot load /etc/httpd/modules/mod_rpa
f-2.0.so into server: /etc/httpd/modules/mod_rpaf-2.0.so: cannot open shared obj
ect file: No such file or directory

[root@localhost ~]# httpd -t
Syntax error on line 4 of /etc/httpd/conf.d/mod_rpaf.conf:
Invalid command 'RPAFenable', perhaps misspelled or defined by a module not incl
uded in the server configuration

А в браузер получаем HTTP 502 Ошибка межсетевого шлюза.

В mod_rpaf-0.6-2.el6.art.x86_64.rpm модуль назывался mod_rpaf-2.0.so, а в версии mod_rpaf-0.8-3.el6.art.x86_64.rpm модуль переименовался в mod_rpaf.so, более того изменились имена директив в конфиг файле /etc/httpd/conf.d/mod_rpaf.conf! Теперь вместо RPAFheader используется RPAF_header, тобишь после каждого RPAF ставится знак подчёркивания!

Порядок действий для устранения ошибок:

yum remove mod_rpaf
rm /etc/httpd/conf.d/mod_rpaf.conf.rpmnew
rm /etc/httpd/conf.d/mod_rpaf.conf.rpmsave
yum install mod_rpaf
 
vi /etc/httpd/conf.d/mod_rpaf.conf
LoadModule rpaf_module modules/mod_rpaf.so
 
<IfModule mod_rpaf.c>
 RPAF_Enable On
 RPAF_ProxyIPs 127.0.0.1
 RPAF_Header X-Forwarded-For
 RPAF_header X-Real-IP
 #RPAF_SetHostName On
 #RPAF_SetHTTPS On
 #RPAF_SetPort On
</IfModule>

Эпилог

На примере детей семейства Apache prefork MPM работающих как backend под frontend-ом Nginx, можно убедится в том, как важно сохранять баланс между сущностями и не плодить их сверх необходимого мхо еже чревато это затяжным кризисом и межусобными войнами.

Главный СисьАдмин человечества видимо где-то загулял или запил и не заметил даже, что конфигурация сервера по имени Земля не выдерживает никакой критики, а подправить то ServerLimit, MaxClients и MaxRequestsPerChild некому или же Он всё правильно настроил, да в процессе что-то глюкануло, хакеры ломанули, а пропатчить то некому, ведь Главный СисьАдмин в загуле - жаль у меня нет доступа к конфигурационным файлам человечества!...

P.S. Дайте мне исходники вселенной и хороший дебагер!

Автор: Олег Головский


Об авторе
АдМинь БагоИскатель
АдМинь БагоИскатель ярый борец за безглючную работу любых механизмов и организмов во всей вселенной и потому пребывает в вечном поиске всяческих багов, а тот кто ищет как известно всегда находит. Когда что-то или кого-то вылечить не в состоянии, то со словами "Я в аду, а вы все черти" уходит в запой выйдя из которого снова берётся лечить неизлечимое.
Ещё статьи автора
Комментарии в блоге
Новое на форуме