Как я победил ошибку 502 Gateway timeout error в nginx+php-fpm
Php-fpm считается на сегодняшний день одним из самых быстрых движков для веб-сервера.
Но он очень нестабилен при работе со сложным php-кодом. И в один прекрасный день вы можете получить ошибку 502 Gateway timeout error.
У меня в проекте так и получилось. На VPS стоял nginx + php7.0-fpm + MariaDB + memcached.
Код php-скрипта использовал весь этот стэк технологий и работал благополучно пару месяцев, а потом вдруг стал выдавать 502-ю.
Для проверки, когда мой скрипт все-таки работает, я написал скрипт-чекер на php и запускал каждые 10 минут его по сron. Чекер запускался через консоль, а обращался через функцию file_get_contents() к url скрипта на сайте.
В случае недоступности скрипта я отсылал через mail() письмо себе на почту.
Я выяснил, что ошибка 502 Gateway timeout error возникала не всегда. Могла появиться раз в час, а могла и на протяжении многих часов.
Временно исправить проблему помогала перезагрузка nginx и memcached.
Почитав мануалы, я решил применить то, что советуют — увеличить proxy timeout в директиве Location, а также timeout в настройках php-fpm.
Не помогло. Причем, когда я вообще сделал timeout в php-fpm бесконечным, скрипту все равно не хватало времени и он выполнялся без конца.
Решив, что все-таки дело в php-fpm я подумал, чем же его заменить. Порывшись в интернете я нашел решение для замены — OpenLightSpeed Webserver + php-модуль к нему.
Установив этот вебсервер, что было не совсем просто, но все же осуществимо в конце концов я обнаружил, что 502-я ошибка появляется все также.
Еще я не смог настроить BasicAuth авторизацию на папках, поэтому недолго думая запустил восстановление бэкапа диска VPS-сервера и через 10 минут снова работал с nginx+php-fpm.
Последнее обстоятельство толкало на новую мысль — дело не в сервере, а в скрипте. И это оказалось правильным.
Я залез в скрипт — там было 5 sql-запросов к mysql. 2 я слил в 1 при помощи LEFT JOIN, из 2-х запросов сделал 1. И еще 1 оставил, как есть.
Исследуя запросы, я обратил внимание на запрос
1 | SELECT max(price) FROM prices WHERE session_id = '1' |
И решил залезть в phpmyadmin, чтобы посмотреть таблицы.
Каково было мое удивление, когда я обнаружил 400000 записей цен.
При этом для этой таблицы не было установлено ни одного индекса. Все. Причины ошибки 502 были найдены!
Был переписан скрипт импорта записей в таблицу цен, а в самой таблице цен созданы индексы.
После проведения работ теперь все работает как надо.
Возможно, что при появлении ошибки 502 Gateway timeout error причина может быть в базе данных и в веб-сервере, а совсем не в php-fpm.
Поэтому в базе данных можно попробовать включить лог медленных запросов (slow query), а в веб-сервере промониторить, появляется ли 502-я ошибка при получении с сервера статических файлов — картинок или css-стилей.