Отладка 504 Gateway Timeout и его фактическая причина и решение

Мы запускаем следующий стек на нашем веб-сервере Varnish + Nginx + FastCGI (php-fpm) на RHEL 6.6

Это динамичный веб-сайт с различными наборами результатов каждый раз и имеет около 2 миллионов URL, проиндексированных с помощью Google.

  • Он работает на nginx/1.5.12 и PHP 5.3.3 (скоро будет обновлен до последних версий nginx и PHP)
  • Nginx подключается к php-fpm, работающему локально на том же сервере через порт 9000

На некоторых страницах мы периодически получаем тайм-аут 504 Gateway, который мы не можем разрешить. URL, которые дают 504, прекрасно работает через некоторое время. Мы узнаем около 504 из наших журналов, и нам не удалось воспроизвести это, так как это случайно происходит на любом URL и работает через некоторое время.

У меня было несколько обсуждений с разработчиком, но, по его мнению, базовый скрипт php почти ничего не делает, и это не должно занимать так много времени (120 секунд), но все равно дает 504 Gateway timeout.

Необходимо установить, где именно проблема возникает:

  • Это проблема с Nginx?
  • Это проблема с php-fpm?
  • Это проблема с базовыми PHP-скриптами?
  • Возможно ли, что nginx не может подключиться к php-fpm?
  • Разрешится ли это, если мы будем использовать Unix-сокет вместо TCP/IP-соединения с?

Время ожидания URL истекает через 120 секунд с 504

Ниже приведена ошибка: 2016/01/04 17:29:20 [ошибка] 1070#0: *196333149 Тайм-аут восходящего потока (110: Тайм-аут соединения) при подключении к восходящему каналу, клиент: 66.249.74.95, сервер: xxxx, запрос: "GET /Some/url HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", хост: "example.com"

Ранее с fastcgi_connect_timeout 150 секунд - раньше он выдавал код состояния 502 через 63 секунды со значением по умолчанию net.ipv4.tcp_syn_retries = 5 на RHEL 6.6; после этого мы установили net.ipv4.tcp_syn_retries = 6, а затем он начал давать 502 через 127 секунд.

Как только я установил fastcgi_connect_timeout = 120, он начал давать код состояния 504. Я понимаю, что fastcgi_connect_timeout с таким высоким значением не годится.

Нужно выяснить, почему именно мы получаем 504 (я знаю его время ожидания, но причина неизвестна). Нужно добраться до первопричины, чтобы исправить это навсегда.

Как я могу подтвердить, где именно проблема?

Вот некоторые из тайм-аутов, уже определенных:

Под сервером nginx.conf:

  • keepalive_timeout 5;
  • send_timeout 150;

под конкретным vhost.conf:

  • proxy_send_timeout 100
  • proxy_read_timeout 100
  • proxy_connect_timeout 100
  • fastcgi_connect_timeout 120
  • fastcgi_send_timeout 300
  • fastcgi_read_timeout 300

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

Ниже приведены некоторые настройки из sysctl.conf:

  • net.ipv4.ip_local_port_range = 1024 65500
  • net.ipv4.tcp_fin_timeout = 10
  • net.ipv4.tcp_tw_reuse = 1
  • net.ipv4.tcp_syn_retries = 6
  • net.core.netdev_max_backlog = 8192
  • net.ipv4.tcp_max_tw_buckets = 2000000
  • net.core.somaxconn = 4096
  • net.ipv4.tcp_no_metrics_save = 1
  • vm.max_map_count = 256000

Если это плохо написанный код, то я должен сообщить разработчику, что 504 происходит из-за проблемы в коде php, а не из-за nginx или php-fpm, и если это из-за Nginx или Php-fpm, то нужно это исправить.

Заранее спасибо!

======

Дальнейшее обновление:

Есть 2 случая:

  1. 504 при 120 секундах с указанной ниже ошибкой:

2016/01/05 03:50:54 [ошибка] 1070#0: *201650845 Тайм-аут восходящего потока (110: Тайм-аут соединения) при подключении к восходящему каналу, клиент: 66.249.74.99, сервер: xxxx, запрос: "GET /some/url HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", хост:" example.com "

  1. 504 @ 300 секунд с указанной ниже ошибкой:

2016/01/05 00:51:43 [error] 1067 # 0: * 200656359 Тайм-аут восходящего потока (110: Тайм-аут соединения) при чтении заголовка ответа из восходящего потока, клиент: 115.112.161.9, сервер: 192.168.12.101, запрос: "GET / some / url HTTP / 1.1", upstream: "fastcgi: //127.0.0.1: 9000", хост: "example.com"

  • В логах php-fpm ошибок не найдено.
  • Количество php-fpm процессов также было нормальным. Backend не выглядит перегруженным, так как другие запросы одновременно выполнялись нормально.

  • Используется только один пул php-fpm. Один основной (родительский) процесс php-fpm и другие подчиненные (дочерние) процессы обычно находятся в нормальном диапазоне только при соблюдении 5xx. Нет значительного роста числа процессов php-fpm, и даже если он растет, у сервера будет достаточно мощности, чтобы раскошелиться на новые и обработать запрос.

3 ответа

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

      ini_set('max_execution_time', '0'); // for infinite time of execution   
ini_set('max_execution_time', '300'); //300 seconds = 5 minutes
ini_set('memory_limit','2048M'); // For unlimited memory limit set -1

It must be assumed that you are rewriting URLs or otherwise redirecting through a gateway/firewall, which is generally how a 504 error arises.

504 means that a backend service (ie, on the other side of the gateway/firewall - the inside) is either down or cannot be addressed (bad internal URL). It can also be caused by a backend crash, but that should show up in the logs (if debug logs are turned on).

Check the following: (a) Check the application by accessing it on the internal network. Can it be addressed? Are the parameters right? Is it working as intended? (b) Check the gateway. How is it redirecting (rewriting) the URL? Have the required modules installed to allow redirection/rewriting? Is the resultant address correct internally? Is the redirection written correctly (correct type, arguments, etc)? Checking the access logs on the gateway may be useful.

However, there are many other ways this problem can occur, but this is the area you should be investigating. 504 is a routing error.

Долгосрочное решение - отредактировать файл /etc/sysctl.conf, включив в него строку:

fs.inotify.max_user_watches=1048576

Вам нужно запустить sysctl -p, чтобы перезагрузить sysctl.conf

СДЕЛАНО.

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