NginX выдает ошибку HTTP 499 через 60 секунд, несмотря на настройки. (PHP и AWS)

В конце прошлой недели я обнаружил проблему в одном из моих средних экземпляров AWS, когда Nginx всегда возвращает ответ HTTP 499, если запрос занимает более 60 секунд. Запрашиваемая страница является PHP-скриптом

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

Я попытался изменить настройки PHP, настройки PHP-FPM и настройки Nginx. Вы можете увидеть вопрос, который я поднял на форумах NginX в пятницу ( http://forum.nginx.org/read.php?9,237692), хотя он не получил ответа, поэтому я надеюсь, что смогу найти Ответ здесь, прежде чем я вынужден вернуться к Apache, который, я знаю, просто работает.

Это не та же проблема, что и ошибки HTTP 500, о которых сообщалось в других записях.

Мне удалось повторить проблему с новым экземпляром NginX micro AWS, используя PHP 5.4.11.

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

Вам нужно будет запустить новый экземпляр AWS Micro (чтобы он был бесплатным) с помощью AMI ami-c1aaabb5

Эта запись PasteBin имеет полную настройку для запуска, чтобы отразить мою тестовую среду. Вам просто нужно изменить example.com в конфигурации NginX в конце

http://pastebin.com/WQX4AqEU

После настройки вам просто нужно создать пример PHP-файла, который я тестирую и который

<?php
sleep(70);
die( 'Hello World' );
?>

Сохраните это в webroot и затем протестируйте. Если вы запустите скрипт из командной строки, используя php или php-cgi, он будет работать. Если вы обращаетесь к сценарию через веб-страницу и подключаете журнал доступа /var/log/nginx/example.access.log, вы заметите, что получите ответ HTTP 1.1 499 через 60 секунд.

Теперь, когда вы видите тайм-аут, я попытаюсь обойти некоторые изменения конфигурации, внесенные в PHP и NginX. Для PHP я создам несколько конфигурационных файлов, чтобы их можно было легко отключить

Обновите PHP FPM Config для включения внешних конфигурационных файлов.

sudo echo '
include=/usr/local/php/php-fpm.d/*.conf
' >> /usr/local/php/etc/php-fpm.conf

Создайте новую конфигурацию PHP-FPM, чтобы переопределить время ожидания запроса.

sudo echo '[www]
request_terminate_timeout = 120s
request_slowlog_timeout = 60s
slowlog = /var/log/php-fpm-slow.log ' >
/usr/local/php/php-fpm.d/timeouts.conf

Измените некоторые глобальные настройки, чтобы интервал аварийного перезапуска составлял 2 минуты.

# Create a global tweaks
sudo echo '[global]
error_log = /var/log/php-fpm.log
emergency_restart_threshold = 10
emergency_restart_interval = 2m
process_control_timeout = 10s
' > /usr/local/php/php-fpm.d/global-tweaks.conf

Далее мы изменим некоторые настройки PHP.INI, снова используя отдельные файлы

# Log PHP Errors
sudo echo '[PHP]
log_errors = on
error_log = /var/log/php.log
' > /usr/local/php/conf.d/errors.ini

sudo echo '[PHP]
post_max_size=32M
upload_max_filesize=32M
max_execution_time = 360
default_socket_timeout = 360
mysql.connect_timeout = 360
max_input_time = 360
' > /usr/local/php/conf.d/filesize.ini

Как видите, это увеличивает время ожидания сокета до 3 минут и поможет регистрировать ошибки.

Наконец, я отредактирую некоторые настройки NginX, чтобы увеличить время ожидания по ту сторону

Сначала я редактирую файл /etc/nginx/nginx.conf и добавляю его в директиву http fastcgi_read_timeout 300;

Затем я редактирую файл /etc/nginx/sites-enabled/example, который мы создали ранее (см. Запись pastebin), и добавляю следующие параметры в директиву сервера.

client_max_body_size    200;
client_header_timeout   360;
client_body_timeout     360;
fastcgi_read_timeout    360;
keepalive_timeout       360;
proxy_ignore_client_abort on;
send_timeout            360;
lingering_timeout       360;

Наконец, я добавляю следующее в папку location ~.php $ директории сервера.

fastcgi_read_timeout 360;
fastcgi_send_timeout 360;
fastcgi_connect_timeout 1200;

Перед повторным запуском скрипта запустите nginx и php-fpm, чтобы убедиться, что новые настройки выбраны. Затем я пытаюсь получить доступ к странице и все равно получаю запись HTTP/1.1 499 в файле NginX example.error.log.

Итак, где я иду не так? Это работает только на apache, когда я устанавливаю максимальное время выполнения PHP 2 минуты.

Я вижу, что настройки PHP были выбраны с помощью phpinfo() со страницы, доступной через Интернет. Я просто не понимаю, я на самом деле думаю, что слишком много было увеличено, так как для этого нужно просто изменить PHP max_execution_time, default_socket_timeout, а также fastcgi_read_timeout NginX в рамках только директивы server->location.

Обновление 1

Проведя дополнительный тест, чтобы показать, что проблема не в том, что клиент умирает, я изменил тестовый файл, чтобы

<?php
file_put_contents('/www/log.log', 'My first data');
sleep(70);
file_put_contents('/www/log.log','The sleep has passed');
die('Hello World after sleep');
?>

Если я запускаю скрипт с веб-страницы, то вижу, что содержимое файла будет установлено в первую строку. Через 60 секунд ошибка появляется в журнале NginX. Через 10 секунд содержимое файла изменяется на 2-ю строку, доказывая, что PHP завершает процесс.

Обновление 2

Включение fastcgi_ignore_client_abort; меняет ответ с HTTP 499 на HTTP 200, хотя конечному клиенту ничего не возвращается.

Обновление 3

Установив Apache и PHP (5.3.10) прямо на коробку (используя apt), а затем увеличивая время выполнения, проблема, по-видимому, также возникает на Apache. Симптомы такие же, как у NginX, ответ HTTP200, но фактическое время ожидания клиентского соединения истекло.

Я также начал замечать в журналах NginX, что если я тестирую с помощью Firefox, он делает двойной запрос (как этот PHP-скрипт выполняется дважды, если он дольше 60 секунд). Хотя это, кажется, клиент, запрашивающий после сбоя сценария

6 ответов

Решение

Причиной проблемы являются упругие балансировщики нагрузки на AWS. По умолчанию время ожидания истекает через 60 секунд бездействия, что является причиной проблемы.

Так что это был не NginX, PHP-FPM или PHP, а балансировщик нагрузки.

Чтобы это исправить, просто перейдите на вкладку "Описание" ELB, прокрутите вниз и нажмите ссылку "(Изменить)" рядом со значением, которое говорит "Время простоя: 60 секунд"

В моем случае - nginx отправлял запрос в AWS ALB и получал тайм-аут с кодом состояния 499.

Решением было добавить эту строку:

proxy_next_upstream off;

Значение по умолчанию для этого в текущих версиях nginx - proxy_next_upstream error timeout; - что означает, что по истечении времени ожидания он пробует следующий «сервер», который в случае ALB является следующим IP в списке разрешенных IP-адресов.

На самом деле, я столкнулся с той же проблемой на одном сервере и обнаружил, что после изменений конфигурации nginx я не перезагружал сервер nginx, поэтому при каждом обращении к URL-адресу nginx я получал 499 http ответ. После перезапуска nginx он начал нормально работать с ответами http 200.

Я думал, что оставлю свои два цента. Во-первых, проблема не связана с php (все еще может быть связана с php, php всегда меня удивляет:P). Это уж точно. в основном это вызвано тем, что сервер проксирован самому себе, более конкретно, проблема имен хостов / псевдонимов, в вашем случае это может быть балансировщик нагрузки, запрашивающий nginx, а nginx вызывает обратный вызов балансировщика нагрузки, и он продолжает идти по этому пути.

У меня возникла похожая проблема с nginx в качестве балансировщика нагрузки и apache в качестве веб-сервера / прокси

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

У нас есть 3 элемента: nginx, php-fpm, php. Как вы сказали, те же настройки php под apache - это нормально. Разве это не то же самое? Вы пробовали apache вместо nginx на той же ОС / хосте и т. Д.?

Если мы увидим, что php не подозревает, у нас есть два подозреваемых: nginx и php-fpm.

Чтобы исключить nginx: попробуйте настроить ту же "систему" ​​на ruby. Смотрите https://github.com/garex/puppet-module-nginx чтобы получить представление об установке простейшей установки ruby. Или воспользуйтесь гуглом (может быть, будет еще лучше).

Мой главный подозреваемый здесь php-fpm.

Попробуйте поиграть с этими настройками:

  • php-fpm`s request_terminate_timeout
  • nginx`s fastcgi_ignore_client_abort

Не уверен, что кто-то еще сталкивался с этим, но для меня это случилось после того, как я поставил / в конце мой экземпляр URL. Это дало 499 ошибку и только после того, как я удалил /Дала мне 200 и все прошло хорошо.

Другие вопросы по тегам