В силу всё большей популярности web-сервера nginx и выходом уже релиза 1.0 решил понемногу переводить свои сервера на nginx. Но для успешной работы web-сайта одного nginx’a нам мало. Нужно ещё заставить выполнять php/cgi скрипты. Об этом собственно речь и пойдёт в статье.
Тестовый стенд: FreeBSD 8.1-RELEASE i386
1) Установка nginx (версия 1.05).
Ставить будем из портов:
#cd /usr/ports/www/nginx && make install clean
В качестве опций я выбрал такие:
[X] HTTP_MODULE Enable HTTP module
[X] HTTP_CACHE_MODULE Enable http_cache module
[X] HTTP_REWRITE_MODULE Enable http_rewrite module
[X] HTTP_STATUS_MODULE Enable http_stub_status module
Настройка сервера достаточно проста. Приводим конфигурационный файл /usr/local/etc/nginx/nginx.conf к такому виду:
#Число процессорных ядер
worker_processes 4;
#Уменьшаем количестве вызовов gettimeofday()
time_resolution 100ms;
error_log /var/log/nginx/error.log;
events {
worker_connections 10240;
use kqueue; # FreeBSD only
multi_accept on;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile off;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
reset_timedout_connection on;
server_tokens off;
client_body_buffer_size 1K;
client_header_buffer_size 1k;
client_max_body_size 1k;
large_client_header_buffers 2 1k;
client_body_timeout 10;
client_header_timeout 10;
send_timeout 10;
gzip on;
gzip_min_length 1000;
gzip_buffers 16 8k;
gzip_types text/plain text/css text/xml application/x-javascript application/xml application/xhtml+xml;
server {
listen 80 default sndbuf=16k rcvbuf=8k accept_filter=httpready;
server_name _;
location / {
root /usr/local/www/nginx;
index index.html index.htm;
}
#restrict all ".files" (.htpasswd, .git,...)
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/www/nginx-dist;
}
}
Примечание.
1) Приоритет рабочих процессов следует изменять с осторожностью, иначе они могут просто “задавить” все остальные сервисы, включая memcached и процессы базы данных. В идеале лучше протестировать работу nginx с дефолтными настройками и лишь затем приступать к экспериментам.
2) Опция use kqueue немного ускоряет работу nginx во FгeeBSD благодаря использованию механизма kqueue вместо более медленного epoll.
3) Системный вызов sendfile() применяется для единовременной отправки содержимого целого файла в сокет. Метод с использованием этого вызова работает быстрее, чем стандартное последовательное копирование данных, и позволяет сэкономить на оперативной памяти. Однако, если сервер оснащен недостаточным количеством ОЗУ, sendfile() только вынудит nginx часто свопиться и тем самым замедлит его работу.
Его лучше использовать, если отдаваемый контент
полностью помещается в оперативную память. aio лучше использовать, когда
оперативы мало, а активного контента – много.
4) Оnция tcp_nopush заставляет nginx отправлять НТТР-заголовки в одном пакете, но она бесполезна без sendfile.
5) GZIР-компрессия также может сыграть с сервером злую шутку. С одной стороны, такая комnрессия уменьшает объем передаваемых сервером данных, благодаря чему он может успеть обработать больше заnросов, с другой – повышает нагрузку на процессор, что приводит к прямо nротивоположному результату. Поэтому точно выяснить, нужна ли она тебе, можно только экспериментальным путем, причем эксnерименты следует проводить под предельной нагрузкой.
Добавляем строку запуска nginx’a в /etc/rc.conf:
#echo 'nginx_enable="YES"' >> /etc/rc.conf'
После, запускаем nginx и смотрим:
#/usr/local/etc/rc.d/nginx start
#sockstat | grep nginx
www nginx 51589 6 tcp4 *:80 *:*
www nginx 51589 10 stream -> ??
root nginx 45280 6 tcp4 *:80 *:*
root nginx 45280 9 stream -> ??
root nginx 45280 10 stream -> ??
2) Установка php (версия 5.3.6_1)
Для версии 5.3 поддержка fpm уже присутствует в ядре php. Для версии 5.2 нужно качать патч.
Ставим из портов:
#cd /usr/ports/lang/php5 && make install clean
В качестве опций я выбрал такие:
[X] CLI Build CLI version
[X] CGI Build CGI version
[X] FPM Build FPM version (experimental)
[X] SUHOSIN Enable Suhosin protection system
После установки приводим конфигурационный файл /usr/local/etc/php-fpm.conf к такому виду:
[global]
pid = run/php-fpm.pid
error_log = log/php-fpm.log
log_level = notice
[www]
listen = /tmp/php-fpm.sock
user = www
group = www
pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 35
где параметры pid и error_log имеют путь относительно каталога /var
Примечание:
Если вы планируете использовать virtualhosts, то рекомендую создавать на каждый сайт отдельный пул, отдельного пользователя, отдельные настройки. Например:
[global]
...
[site1]
user=site1
group=www
listen=/tmp/php-fpm_site1.sock
...
[site2]
user=site2
group=www
listen=/tmp/php-fpm_site2.sock
...
Это добавит безопасности и независимости сайтов друг от друга
Добавляем строку запуска nginx’a в /etc/rc.conf:
#echo 'php_fpm_enable="YES"' >> /etc/rc.conf'
После, запускаем php_fpm и смотрим:
#/usr/local/etc/rc.d/php-fpm start
#sockstat | grep php-fpm
www php-fpm 45316 0 stream /tmp/php-fpm.sock
www php-fpm 45315 0 stream /tmp/php-fpm.sock
www php-fpm 45314 0 stream /tmp/php-fpm.sock
www php-fpm 45313 0 stream /tmp/php-fpm.sock
www php-fpm 45312 0 stream /tmp/php-fpm.sock
www php-fpm 45311 0 stream /tmp/php-fpm.sock
www php-fpm 45310 0 stream /tmp/php-fpm.sock
www php-fpm 45309 0 stream /tmp/php-fpm.sock
www php-fpm 45308 0 stream /tmp/php-fpm.sock
www php-fpm 45307 0 stream /tmp/php-fpm.sock
www php-fpm 45306 0 stream /tmp/php-fpm.sock
www php-fpm 45305 0 stream /tmp/php-fpm.sock
www php-fpm 45304 0 stream /tmp/php-fpm.sock
www php-fpm 45303 0 stream /tmp/php-fpm.sock
www php-fpm 45302 0 stream /tmp/php-fpm.sock
www php-fpm 45301 0 stream /tmp/php-fpm.sock
www php-fpm 45300 0 stream /tmp/php-fpm.sock
www php-fpm 45299 0 stream /tmp/php-fpm.sock
www php-fpm 45298 0 stream /tmp/php-fpm.sock
www php-fpm 45297 0 stream /tmp/php-fpm.sock
root php-fpm 45296 4 stream -> ??
root php-fpm 45296 5 stream -> ??
root php-fpm 45296 6 stream /tmp/php-fpm.sock
Теперь осталось изменить конфигурационный файл nginx’a так, что бы выполнение php-скриптов он передавал сокету /tmp/php-fpm.sock. Для этого добавляем такой код в файл nginx.conf, в секцию server :
server {
...
location ~ \.php$ {
root /usr/local/www/nginx;
fastcgi_pass unix:/tmp/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include /usr/local/etc/nginx/fastcgi_params;
}
...
Так же в блоке ‘location / {‘ меняем строку
index index.html index.htm;
на такую
index index.php index.html index.htm;
Теперь наш кореневой сайт может выполнять php-скрипты. А что если нам нужно добавить алиас и что бы в нём тоже выполнялись php-скрипты? Тогда добавляем такие блоки:
location /cacti {
alias /usr/local/www/cacti;
index index.php;
}
location ~ ^/cacti/(.*\.php)$ {
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /usr/local/www/cacti/$1;
fastcgi_param DOCUMENT_ROOT /usr/local/www/cacti;
fastcgi_pass unix:/tmp/php-fpm.sock;
include /usr/local/etc/nginx/fastcgi_params;
}
После этого перечитываем конфиг nginx’a и наслаждаемся успешной работой:
#/usr/local/etc/rc.d/nginx reload
3) Установка perl’a.
Подразумевается, что perl у вас уже установлен. Если нет, тогда ставьте версию 5.14 из портов.
Выполнять perl-скрипты мы тоже будем через FastCGI. В качестве обработчика мы выбрали fcgiwrap, который уже есть в портах. Ставим его:
#cd /usr/ports/www/fcgiwrap && make install clean
После установки добавляем такие строки в /etc/rc.conf:
fcgiwrap_enable="YES"
fcgiwrap_socket="unix:/var/run/fcgiwrap/fcgiwrap.sock"
fcgiwrap_user="www"
и запускаем:
#/usr/local/etc/rc.d/fcgiwrap start
#sockstat | grep fcgiwrap
www fcgiwrap 52145 0 stream /var/run/fcgiwrap/fcgiwrap.sock
Теперь переходим к настройкам nginx’a. Добавляем такий блок в секцию server:
location /cgi-bin2 {
alias /usr/local/www/cgi-bin2;
fastcgi_pass unix:/var/run/fcgiwrap/fcgiwrap.sock;
fastcgi_param SCRIPT_FILENAME /usr/local/www$fastcgi_script_name;
fastcgi_param SCRIPT_NAME /usr/local/www$fastcgi_script_name;
include /usr/local/etc/nginx/fastcgi_params;
}
Перечитываем конфиг nginx’a и радуемся:
#/usr/local/etc/rc.d/nginx reload
4) Установка eAccelerator (версия 0.9.6.1_1)
eAccelerator является PHP-акселератором, основное назначение которого состоит в кэшировании бинарного представления кода. Каждый раз при выполнении скрипта, PHP читает все подключаемые файлы и переводит их в бинарный код, при запросе скрипта операция повторяется. Задача eAccelerator состоит в сохранении бинарного кода для повторного использования, уменьшая время выполнения скрипта.
Внимание! eAccelerator работает с PHP в режиме fastcgi или mod_php.
Ставим из портов:
#cd /usr/ports/www/eaccelerator && make install clean
После установки открываем файл php.ini и вносим такие строки:
extension="eaccelerator.so"
eaccelerator.shm_size="32"
eaccelerator.cache_dir="/var/spool/eaccelerator"
eaccelerator.enable="1"
eaccelerator.optimizer="1"
eaccelerator.check_mtime="1"
eaccelerator.debug="0"
eaccelerator.filter=""
eaccelerator.shm_max="0"
eaccelerator.shm_ttl="3600"
eaccelerator.shm_prune_period="1800"
eaccelerator.shm_only="0"
eaccelerator.compress="1"
eaccelerator.compress_level="9"
После этого создаём директорию для кэша и назначаем соответствующие права:
#mkdir /var/spool/eaccelerator
#chmod 0700 /var/spool/eaccelerator
#chown www /var/spool/eaccelerator
После этого перезапускаем php-fpm:
#/usr/local/etc/rc.d/php-fpm reload
5) Accept-фильтры.
В 2000-ом году FreeBSD появились accept-фильтры. Они позволяют не передавать в accept() пришедшее соединение до тех пор, пока не придёт первый пакет с данными (фильтр dataready) или заголовок HTTP-запроса (фильтр httpready). Использование фильтров в Apache (а в нём они поддерживаются, начиная с версии 1.3.14) позволяет уменьшить число процессов. В серверах, использующих select(), poll() или kqueue(), например, в thttpd-2.22, фильтры уменьшают число открытых файлов. И наконец, в обоих случаях accept-фильтры уменьшают число переключений контекста процесса. (Взято с сайта Игоря Сысоева)
То есть они позволяют ускорять работу nginx’a. Замечу, что этот параметр работает только во FreeBSD. И так, для включения работы фильтров нужно либо пересобрать ядро с опциями
options ACCEPT_FILTER_HTTP
options ACCEPT_FILTER_DATA
Либо одну из них, в зависимости от того, какой фильтр вы будете использовать.
Если не хотите пересобирать ядро, можно подгрузить модули:
#kldload accf_http
#kldload accf_data
Если вы подгружаете модули, не забудьте добавить такие строки в /boot/loader.conf:
accf_http_load=YES
accf_data_load=YES
После этого переходим к настройке nginx’a. Вот какой параметр за это отвечает:
accept_filter=фильтр — задаёт название accept-фильтра. Работает только на FreeBSD, можно использовать два фильтра — dataready и httpready. По сигналу -HUP accept-фильтр можно менять только в последних версиях FreeBSD, начиная с 6.0, 5.4-STABLE и 4.11-STABLE.
Вот как будет выглядеть строка в конфиге nginx.conf:
listen 1.2.3.4:80 default sndbuf=16k rcvbuf=8k accept_filter=httpready;
6) Работа с сессиями php.
При использовании сессий в php, по умолчанию они сохраняются в /tmp и со временем забивают раздел. Что бы этого не произошло, нужно сделать так:
– изменить путь хранения сессий (в php.ini меняем параметр session.save_path = “/var/lib/php5” ну или другую папку, где места предостаточно)
– проверить значение переменных session.gc_probability и session.gc_divisor, что бы дробь session.gc_probability/session.gc_divisor существовала и имела более-менее нормальное значение
– настроить по крону сборщик мусора (garbage collector). Пример для debian’a
09,39 * * * * root [ -x /usr/lib/php5/maxlifetime ] && [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 -maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) ! -execdir fuser -s {} 2>/dev/null \; -delete
Ложка дёгтя.
При установке на один из серверов появлялась ошибка в логах php-fpm:
[28-Jul-2011 12:36:28] WARNING: [pool www] child 2273 exited on signal 11 (SIGSEGV) after 2172.202986 seconds from start
[28-Jul-2011 12:36:28] NOTICE: [pool www] child 12535 started
[28-Jul-2011 12:36:35] WARNING: [pool www] child 2266 exited on signal 11 (SIGSEGV) after 2178.624133 seconds from start
[28-Jul-2011 12:36:35] NOTICE: [pool www] child 12552 started
При этом php-скрипты работали через раз: один раз работают, другой раз – пишет Сервис недоступен. Ну и когда писалось “Сервис недоступен”, то в логах как раз светились заветные строки.
Как вариант лечения, я добавил такую строку
fastcgi_param PHP_ADMIN_VALUE "open_basedir=/usr/local/share/cacti/:/var/tmp/";
к блоку описания fastcgi для каждого из location’ов (пример приведён для location’а cacti). Может это быть связано с тем, что я использовал параметр open_basedir в описании location’a nagios. После этого всё заработало так, как должно быть.
7) Ссылки
https://habrahabr.ru/post/260669/
https://www.packtpub.com/books/content/fine-tune-nginx-configufine-tune-nginx-configurationfine-tune-nginx-configurationratio
2 коментарі “[nginx] Быстрый и производительный web сервера на nginx”
Подскажите пожалуйста у меня такая же проблема
[28-Jul-2011 12:36:28] WARNING: [pool www] child 2273 exited on signal 11 (SIGSEGV) after 2172.202986 seconds from start
[28-Jul-2011 12:36:28] NOTICE: [pool www] child 12535 started
подскажите куда нужно это добавить
fastcgi_param PHP_ADMIN_VALUE “open_basedir=/usr/local/share/cacti/:/var/tmp/”;
Заранее большое спасибо.
Это нужно добавить в блок
location ~ ^/cacti/(.*\.php)$ {
(ну или как оно у вас там называется).