Я использую код для отправки чуть более 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 попыток, которые он должен предпринять.
Я вижу, что есть много похожих запросов о сбоях сервера и переполнении стека. Я подробно описываю их здесь, чтобы этот вопрос не был отмечен как дубликат.
Serverfault - запросы никогда не ставятся в очередь после pm.max_children с Nginx и PHP-FPM. Похоже, это очень похожий вопрос, но на него нет ответов, хотя он был опубликован 3 года назад, и в нем гораздо меньше деталей, чем здесь. Также, некоторые моих запросов должно быть успешно поставлено в очередь, в отличие от вопроса, который предполагает, что как только будет достигнут максимум, все запросы будут отброшены.
ServerFault - nginx ERROR 502 & Resource временно недоступен) при подключении к восходящему потоку, клиенту. Этот пост кажется похожим (он описывает ту же проблему), но, как указано в одном из ответов, его файлы сокетов не совпадают, а мои - нет. Мой /etc/php/7.0/fpm/pool.d/www.conf
конфигурационный файл имеет:
слушайте = /run/php/php7.0-fpm.sock
Вы можете увидеть строки с файлом сокета в сообщениях об ошибках, которые предоставляет nginx.
ServerFault - нужно увеличить пропускную способность nginx для восходящего сокета unix - настройка ядра linux? Ответ здесь предлагал установить net.core.somaxconn
и net.core.netdev_max_backlog
которые я установил на 4096 и 1000 соответственно. Проблема все еще сохраняется.
ServerFault - ошибка php-fpm.sock (11: ресурс временно недоступен) при подключении к восходящему потоку - предлагается установить pm = ondemand и max_children на 4000. Это не подходит для меня, так как это может привести к тому, что мой четырехъядерный сервер будет иметь 4000 потоков и просто съест память.
я верить Nginx работает слишком быстро для PHP-fpm. В какой-то момент fpm просто не отвечает на запрос nginx, поэтому Nginx сдается и отправляет обратно ошибку 502. Есть ли способ (возможно, переменная конфигурации или две) исправить это, чтобы fpm ставил запросы в очередь или повторял попытку nginx позже (fastcgi_next_upstream_tries
похоже, не имеет никакого эффекта)? Я не против как длинный веб-сервер должен обслуживать все запросы (увеличивать тайм-ауты), только я могу установить количество процессов в fpm, соответствующее моему процессору, и все эти 160 запросов будут обслужены.
Я просто попытался заменить 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
)