Назад | Перейти на главную страницу

Поиск узкого места Nginx / PHP-FPM, вызывающего случайные ошибки шлюза 502

Я работаю на довольно загруженном интернет-сайте, который часто получает очень большие всплески трафика. Во время этих всплесков запрашиваются сотни страниц в секунду, что приводит к случайным 502 ошибкам шлюза.

Теперь мы запускаем Nginx (1.0.10) и PHP-FPM на машине с 4-мя дисками SAS 15k (raid10) с 16-ядерным процессором и 24 ГБ оперативной памяти DDR3. Также мы используем последнюю версию Xcache. БД находится на другом компьютере, но нагрузка на этот компьютер очень мала и не вызывает никаких проблем.

При нормальной нагрузке все работает идеально, загрузка системы ниже 1, а отчет о состоянии PHP-FPM никогда не показывает более 10 активных процессов одновременно. Всегда доступно около 10 ГБ оперативной памяти. При нормальной нагрузке машина обрабатывает около 100 просмотров страниц в секунду.

Проблема возникает, когда прибывают огромные всплески трафика, и сотни просмотров страниц в секунду запрашиваются с машины. Я заметил, что в отчете о состоянии FPM отображается до 50 активных процессов, но это все еще намного меньше 300 максимальных подключений, которые мы настроили. Во время этих всплесков состояния Nginx сообщает о 5000 активных подключениях вместо обычных 1000.

Информация об ОС: CentOS версии 5.7 (окончательная)

Процессор: Intel (R) Xeon (R) CPU E5620 @ 2,40 ГГц (16 ядер)

php-fpm.conf

daemonize = yes
listen = /tmp/fpm.sock
pm = static
pm.max_children = 300
pm.max_requests = 1000

Я не устанавливал rlimit_files, потому что, насколько я знаю, он должен использовать системные значения по умолчанию, если вы этого не сделаете.

fastcgi_params (только добавленные значения в стандартный файл)

fastcgi_connect_timeout 60;
fastcgi_send_timeout 180;
fastcgi_read_timeout 180;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;

fastcgi_pass            unix:/tmp/fpm.sock;

nginx.conf

worker_processes        8;
worker_connections      16384;
sendfile                on;
tcp_nopush              on;
keepalive_timeout       4;

Nginx подключается к FPM через Unix Socket.

sysctl.conf

net.ipv4.ip_forward = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
kernel.sysrq = 1
kernel.core_uses_pid = 1
net.ipv4.tcp_syncookies = 1
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.tcp_timestamps = 0
net.ipv4.conf.all.rp_filter=1
net.ipv4.conf.default.rp_filter=1
net.ipv4.conf.eth0.rp_filter=1
net.ipv4.conf.lo.rp_filter=1
net.ipv4.ip_conntrack_max = 100000

limits.conf

* soft nofile 65536
* hard nofile 65536

Это результаты для следующих команд:

ulimit -n
65536

ulimit -Sn
65536

ulimit -Hn
65536

cat /proc/sys/fs/file-max
2390143

Вопрос: Если в PHP-FPM не заканчиваются соединения, нагрузка по-прежнему низкая и имеется много доступной оперативной памяти, какое узкое место может вызывать эти случайные ошибки шлюза 502 во время высокого трафика?

Примечание: по умолчанию ulimit этой машины равнялся 1024, так как я изменил его на 65536, я не перезагружал полностью машину, так как это производственная машина, и это будет означать слишком много времени простоя.

Спорадические ошибки 502 от балансировщиков нагрузки, таких как HAProxy и nginx, обычно вызваны тем, что что-то прерывается в середине потока между LB и веб-сервером.

Попробуйте запустить один из своих веб-серверов или его тестовую копию через GDB и посмотрите, видите ли вы ошибку сегментации при генерации тестового трафика (используйте ab, jMeter или аналогичный для имитации трафика).

Недавно мне пришлось решать очень похожий сценарий / проблему. Я исключил ресурсы и т. Д., Вызывающие проблему, так как у меня был довольно всесторонний мониторинг, который мне помогал. В конце концов я обнаружил, что ошибка 502 исходила от веб-сервера за балансировщиком нагрузки, возвращающего недопустимые (в данном случае пустые) HTTP-ответы на LB.

Я взял один из веб-серверов и остановил веб-сервер, затем снова запустил его через gdb, а затем просмотрел сайт. В конце концов, после некоторого щелчка мышью я увидел, что произошла ошибка сегментации, и это привело к появлению ошибки 502. Я взял трассировку из GDB и отправил ее команде PHP как ошибку, но единственным исправлением для меня было переключение дистрибутива на обход ошибки PHP, которая была там.

Из-за segfault веб-сервер отправлял недопустимый контент в LB, а LB отображал ошибку 502, потому что, насколько это было возможно, веб-сервер исчез «в середине потока».

Я знаю, что это не дает прямого ответа на ваш вопрос, но стоит начать поиски. Предполагая, что вы действительно видите segfault, вы можете получить трассировку стека из GDB, тогда вы можете, надеюсь, работать в обратном направлении и найти, какая функция вызывает ошибку сегментации.

Официальная рекомендация: worker_processes = количество ядер CPU

устанавливать worker_processes 16;