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

Nginx с PHP FPM - ресурс временно недоступен - ошибка 502

Nginx с PHP FPM - ресурс временно недоступен - ошибка 502

Я использую код для отправки чуть более 160 запросов GET асинхронно с использованием curl к моему API, на котором запущен Nginx с Php-fpm на сервере Ubuntu 16.04. Каждый запрос извлекает различный набор данных из базы данных, прежде чем вернуть его в виде ответа JSON. Это количество запросов достаточно мало, поэтому я считаю, что оно не должно достигать каких-либо ограничений по умолчанию (количество подключений к сокетам, дескрипторы файлов и т. Д.). Однако тот факт, что все они отправляются / принимаются одновременно, вызывает проблемы.

Подавляющее большинство запросов будут выполнены, но пара (последовательно одно и то же число в последовательных тестах, но различающихся в зависимости от конфигурации) получат ответ «502 Bad Gateway».

Если я посмотрю журнал ошибок nginx (/var/log/nginx/error.log), Я вижу следующие сообщения об ошибках:

2017/11/21 09:46:43 [error] 29#29: *144 connect() to unix:/run/php/php7.0-fpm.sock failed (11: Resource temporarily unavailable) while connecting to upstream, client: 192.168.3.7, server: , request: "GET /1.0/xxx HTTP/1.1", upstream: "fastcgi://unix:/run/php/php7.0-fpm.sock:", host: "my.domain.org"

Всегда есть именно то же самое в числе сообщений об ошибках «502 Bad Gateway» в журнале, которые я получил обратно от API.

Между тем, при просмотре файла журнала fpm во время выполнения теста (с tail -100f /var/log/php7.0-fpm.log), Ничего не произошло. В нем просто следующее:

[21-Nov-2017 11:54:29] NOTICE: fpm is running, pid 329
[21-Nov-2017 11:54:29] NOTICE: ready to handle connections
[21-Nov-2017 11:54:29] NOTICE: systemd monitor interval set to 10000ms

Хотя моя конфигурация fpm (на /etc/php/7.0/fpm/php-fpm.conf) указывает журнал ошибок с error_log = /var/log/php7.0-fpm.log, похоже, такого файла нет, что говорит об отсутствии ошибок.

Рабочая конфигурация

Я обнаружил, что если я настрою конфигурацию fpm, я могу заставить веб-сервер работать (без ошибок 502), если я настрою /etc/php/7.0/fpm/pool.d/www.conf файл, чтобы использовать static количество 15 потоков, а не динамически порождающих процессов или использования меньшего количества статических процессов.

pm = static
pm.max_children = 15

Я считаю, что это работает, потому что уже есть достаточно потоков, готовых к работе, чтобы принять внезапный удар, и нет никакой задержки, связанной с созданием или закрытием потоков. Однако это означает, что мой веб-сервер будет использовать гораздо больше памяти, чем мне хотелось бы. В идеале я бы хотел pm.max_children быть числом, равным двукратному количеству виртуальных ЦП на сервере (то есть 8 или меньше). В этом случае я использую четырехъядерный сервер, но хотел бы, возможно, масштабировать вниз к двухъядерному экземпляру. В идеале я бы хотел, чтобы сервер ответил все запросов вовремя, даже если общее затраченное время намного больше, например очередь и настройка таймаутов.

Настройки конфигурации

По умолчанию php-fpm listen.backlog ценность 511, но я установил его на 2000, чтобы исключить его влияние. listen.backlog = 2000

Для Nginx я установил 1024 worker_connections и worker_processes auto;, так что должно быть 4.

У меня также есть следующие настройки буфера и тайм-аута, чтобы попытаться предотвратить их влияние:

##
# Buffere settings
##
client_body_buffer_size 10M;
client_header_buffer_size 1k;
client_max_body_size 512m;
large_client_header_buffers 2 1k;


##
# Timeout settings
##
client_body_timeout 120;
client_header_timeout 120;
keepalive_timeout 120;
send_timeout 120;
fastcgi_connect_timeout 60s;
fastcgi_next_upstream_timeout 40s;
fastcgi_next_upstream_tries 10;
fastcgi_read_timeout 60s;
fastcgi_send_timeout 60s;
fastcgi_cache_lock_timeout 60s;

Стоит отметить, что мы получаем все запросы (включая 502) примерно за 20 секунд, поэтому мы не достигаем их. Кроме того, хотя fastcgi_next_upstream_tries установлено значение 10, я получаю только 1 сообщение о недоступности ресурса для каждого сообщения об ошибке 502, а не в 10 раз больше, чем для 10 попыток, которые он должен предпринять.

Похожие / связанные вопросы

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

Вы можете увидеть строки с файлом сокета в сообщениях об ошибках, которые предоставляет nginx.

Вопрос

я верить Nginx работает слишком быстро для PHP-fpm. В какой-то момент fpm просто не отвечает на запрос nginx, поэтому Nginx сдается и отправляет обратно ошибку 502. Есть ли способ (возможно, переменная конфигурации или две) исправить это, чтобы fpm ставил запросы в очередь или повторял попытку nginx позже (fastcgi_next_upstream_tries похоже, не имеет никакого эффекта)? Я не против как длинный веб-сервер должен обслуживать все запросы (увеличивать тайм-ауты), только я могу установить количество процессов в fpm, соответствующее моему процессору, и все эти 160 запросов будут обслужены.

Обновление - отлично работает с использованием сокетов TCP

Я просто попытался заменить FPM из прослушивания файлового сокета unix на сокеты TCP, как подробно описано Вот.

Например. изменение fpm на: Listen 127.0.0.1:9000 и обновление nginx для использования: fastcgi_pass 127.0.0.1:9000;

Похоже, это сработало в качестве обходного пути. Например. Я не получаю ошибок 502, даже если я использую динамический пул или даже статический пул с потоками всего 2 fpm.

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

Я считаю, что вы можете использовать ngx_http_limit_req_module для этого нужно настроить число на желаемое число оборотов в секунду и использовать пакет для установки размера очереди с конфигурацией, подобной следующей:

limit_req_zone $binary_remote_addr zone=php:10m rate=2r/s;

server {
    location ~ \.php$ {
        limit_req zone=php burst=10;
    }

В этом примере будет разрешено в среднем 2 запроса в секунду, с третьим по десятый запросы (если таковые имеются). Если больше 10 об / с 503 будет возвращена ошибка (limit_req_status)