504 Gateway Timeout: медленные бэкенды, таймауты и разница с 502 и 503
Ответ 504 Gateway Timeout означает, что прокси достучался до вашего бэкенда, подождал ответа и сдался раньше, чем ответ пришел. Ничего не упало и никто не отказал в запросе: что-то за прокси работает медленнее, чем прокси готов ждать.
О чем сообщает 504
RFC 9110 определяет 504 для сервера в роли шлюза или прокси, который не получил своевременного ответа от сервера выше по цепочке. Слово «своевременный» задается конфигурацией, а не спецификацией, поэтому 504 это всегда утверждение сразу о двух вещах: насколько медленным был бэкенд и какой лимит выставили прокси.
Отсюда важное практическое следствие. Когда прокси возвращает 504, бэкенд обычно продолжает работать над запросом. Соединение с клиентом уже разорвано, а медленный запрос к базе все еще выполняется, отчет все еще формируется, ресурсы все еще заняты. Поэтому волна ошибок 504 часто делает серверу хуже: каждый брошенный запрос оставляет за собой работу, и очередь растет быстрее, чем разгребается.
504 против 502 и 503
| 502 Bad Gateway | 503 Service Unavailable | 504 Gateway Timeout | |
|---|---|---|---|
| Что произошло | Бэкенд отдал некорректный ответ или закрыл соединение | Сервер намеренно отказался от работы | Бэкенд принял работу и не ответил вовремя |
| Состояние бэкенда | Лежит, падает или говорит не на том протоколе | Работает, но перегружен или на техработах | Работает и занят, все еще обрабатывает |
| Скорость ответа | Обычно мгновенно | Обычно мгновенно | Медленно, приходит по границе таймаута |
| Типичная строка в журнале | connect() failed или upstream prematurely closed connection | Правило техработ или отсутствие живых апстримов | upstream timed out (110: Connection timed out) |
Retry-After | Обычно нет | Часто есть и рекомендуется | Обычно нет |
| Куда смотреть первым делом | Запущен ли процесс бэкенда? | Емкость, флаги техработ, проверки здоровья | Медленные запросы и медленные зависимости |
На практике 502 падает быстро, 503 вежливо отказывает, а 504 сначала заставляет ждать. Отдельное руководство по 502 и обзор семейства 5xx разбирают два других кода целиком.
Почему бэкенд слишком медленный
- Медленные запросы к базе данных. Отсутствующий индекс, запрос, выросший вместе с данными, паттерн N+1 в цикле или борьба за блокировки при конкурентной нагрузке. Самая частая причина.
- Медленные вызовы сторонних сервисов. Исходящий запрос к API без собственного таймаута наследует худший день удаленного сервиса и передает его вашим посетителям.
- Холодный старт. Первый запрос после масштабирования, старта контейнера или простоя оплачивает инициализацию, установку соединений и прогрев кэша разом.
- Действительно тяжелая работа внутри веб-запроса. Формирование отчетов, выгрузки, обработка изображений или массовый импорт в синхронном режиме рано или поздно превысят любой разумный таймаут.
- Борьба за ресурсы. Насыщение процессора, нехватка памяти и своп замедляют каждый запрос, поэтому границу первыми пересекают самые медленные.
- Слишком жесткие таймауты. Если адресу законно нужно больше времени, чем разрешает прокси, ошибка в конфигурации, а не в коде.
- Проблемы сети между шагами. Потери пакетов или задержки разрешения имен для адреса апстрима добавляют время, которого не видно в замерах приложения.
Как разобрать и починить 504
- Измерьте время до ошибки. Задержка перед 504 обычно совпадает с настроенным таймаутом, и по ней видно, какой шаг ее выдал:
Ошибка 504 почти ровно на 60 секундах указывает на стандартный таймаут чтения у прокси. На 30 или 100 секундах она указывает на тот компонент, где выставлено это число, часто на CDN, а не на ваш собственный прокси.curl -sS -o /dev/null -w "%{http_code} %{time_total}s\n" https://example.com/slow-page - Выясните, один это адрес или все. Один медленный URL это проблема приложения. Медленно везде и сразу это насыщение ресурсов или отказавшая зависимость.
- Прочитайте журнал ошибок прокси. В nginx строка вполне однозначна:
В ней названы апстрим и фаза, а это отделяет медленное соединение от медленного ответа.[error] upstream timed out (110: Connection timed out) while reading response header from upstream, upstream: "http://127.0.0.1:8080/" - Замерьте бэкенд напрямую, мимо прокси. Если тот же запрос к источнику занимает 90 секунд, прокси говорит правду, и чинить надо приложение.
- Профилируйте медленный путь. Посмотрите журнал медленных запросов, затем трассировки приложения. Большинство ошибок 504 сводится к одному запросу или одному исходящему вызову.
- Устраните причину, а не таймаут. Добавьте индекс, закэшируйте дорогой результат или вынесите действительно долгую работу в фоновую задачу, которая отвечает сразу и сообщает о прогрессе отдельно.
- Поднимайте таймаут только там, где работа законно длинная, и поднимайте его согласованно на каждом шаге. Лимит CDN в 30 секунд обесценивает таймаут источника в 120 секунд.
- Ставьте таймауты на собственные исходящие вызовы, чтобы медленная зависимость падала быстро и с внятной ошибкой, а не занимала воркер, пока прокси не сдастся.
Время ответа как раннее предупреждение
Ошибка 504 это финал замедления, которое копилось задолго до нее. Время ответа сползает с половины секунды до двух, потом до десяти, и никто этого не замечает, пока запросы не начинают пересекать лимит. Проверка HTTP по расписанию пишет время ответа рядом с кодом состояния, поэтому тренд виден на графике задолго до первого таймаута, а оповещение приходит на первом реальном отказе, а не после того, как наполнится очередь поддержки. Проверка из нескольких регионов тоже помогает: маршрут, быстрый с одного континента и медленный с другого, указывает на сеть или настройку края, а не на вашу базу данных.