504 Gateway Timeout: причины и решения для админов
Ошибка 504 Gateway Timeout возникает, когда прокси (nginx, Cloudflare) ждал ответ от upstream дольше, чем разрешено timeout'ом. В отличие от 502 (невалидный ответ), 504 — это ожидание, которое истекло. Разберём причины, как настроить timeout'ы правильно и как оптимизировать медленные запросы, вместо того чтобы просто их скрывать.
Что означает 504
Согласно RFC 9110 §15.6.5, 504 означает, что сервер, действуя как gateway, не получил своевременный ответ от upstream. Ключевое слово — «своевременный»: таймаут устанавливается в конфиге прокси.
6 частых причин 504
- Медленный SQL-запрос без индекса, блокирующий транзакцию.
- Медленный внешний API документацию, который зависит от third-party.
- Неоптимальный код — N+1 query, не-батчированные операции.
- Ресурсоёмкие задачи в request/response цикле (генерация PDF, отправка email).
- Низкий timeout в nginx/Cloudflare для реально долгих операций.
- Upstream заблокирован — deadlock в БД, заблокированный поток.
Диагностика медленных запросов
# Top медленных запросов в access.log
awk '$10 > 5' /var/log/nginx/access.log | head -20
# MySQL slow log
mysqldumpslow -t 10 /var/log/mysql/slow.log
# PHP-FPM slow log
# /etc/php/8.4/fpm/pool.d/www.conf:
# slowlog = /var/log/php/www-slow.log
# request_slowlog_timeout = 5s
tail -100 /var/log/php/www-slow.log
# Node.js: event loop lag
// npm install clinic
// clinic doctor -- node app.jsПроверьте внешнее время ответа через PageSpeed Check от Enterno.io — получите TTFB, метрики Web Vitals и узкие места.
Правильная настройка timeout в nginx
http {
# Соединение с upstream
proxy_connect_timeout 10s;
# Отправка запроса upstream'у
proxy_send_timeout 30s;
# Чтение ответа от upstream
proxy_read_timeout 60s;
# Для FastCGI (PHP-FPM)
fastcgi_connect_timeout 10s;
fastcgi_send_timeout 30s;
fastcgi_read_timeout 60s;
}
# Long-polling эндпоинт — отдельный location
location /api/long-poll {
proxy_read_timeout 300s; # 5 минут
proxy_pass http://backend;
}PHP-FPM: max_execution_time
# php.ini
max_execution_time = 30
max_input_time = 60
# Для экспорта больших данных:
# Установите per-request через ini_set()
ini_set('max_execution_time', 300); # 5 минут
set_time_limit(300);
# Но лучше вынести в очередь!Node.js: server timeout
const server = app.listen(3000);
server.setTimeout(60000); // 60 секунд
server.keepAliveTimeout = 61000;
server.headersTimeout = 65000; // должен быть > keepAliveTimeout
// Для Fastify
const app = Fastify({
connectionTimeout: 60000,
keepAliveTimeout: 61000,
});Правильное решение: вынос в background
Увеличивать timeout до бесконечности — антипаттерн. Правильное решение — вынести долгие операции в очередь.
// Плохо: блокируем request
app.post('/generate-report', async (req, res) => {
const pdf = await generateBigPDF(req.body); // 3 минуты
await sendEmail(pdf);
res.json({ok: true});
});
// Хорошо: очередь + уведомление
app.post('/generate-report', async (req, res) => {
const jobId = await queue.add('generate-report', req.body);
res.status(202).json({jobId, status: 'queued'});
});
// Worker обрабатывает в фоне
queue.process('generate-report', async (job) => {
const pdf = await generateBigPDF(job.data);
await sendEmail(pdf);
});Клиент получает 202 Accepted + jobId, опрашивает статус через /jobs/:id или получает уведомление через WebSocket/webhook.
Оптимизация медленных запросов БД
-- Ищите long queries
SHOW PROCESSLIST;
SHOW FULL PROCESSLIST;
-- EXPLAIN плана запроса
EXPLAIN SELECT * FROM orders WHERE user_id = 1 ORDER BY created_at DESC LIMIT 10;
-- Добавьте индекс если нужен
CREATE INDEX idx_orders_user_created ON orders(user_id, created_at DESC);
-- Проверьте размеры таблиц
SELECT table_name, ROUND(data_length/1024/1024) AS mb
FROM information_schema.tables
WHERE table_schema = 'your_db'
ORDER BY data_length DESC LIMIT 10;Cloudflare 504 — специфика
Cloudflare имеет жёсткий лимит 100 секунд на free/pro плане. Варианты:
- Использовать Enterprise plan (до 6000 сек).
- Перевести долгие эндпоинты на Origin bypass через отдельный поддомен без CF proxy.
- Оптимизировать код до <100 сек (правильный подход).
Часто задаваемые вопросы (FAQ)
В: Чем 504 отличается от 502?
О: 504 — upstream не ответил в срок. 502 — upstream ответил невалидно или закрыл connection.
В: Какой timeout адекватен?
О: Web-запросы: 30-60 сек. API: 10-30 сек. Long-polling: 300+ сек. Долгие задачи: выносим в очередь.
В: Как поймать 504 автоматически?
О: Enterno.io Monitors с коротким timeout триггерят алерт. Также встройте APM (Sentry, New Relic).
В: Влияет ли 504 на SEO?
О: Да, критично. Googlebot имеет свой timeout (~30 сек). Систематические 504 ведут к деиндексации.
Заключение
504 — не баг timeout'а, а симптом медленного кода или внешнего API. Мониторьте slow log, оптимизируйте запросы, выносите долгие задачи в очередь. Timeout'ы настраивайте с запасом, но не бесконечно. Подключите Enterno.io для автоматической фиксации 504 по регионам.
Проверьте ваш сайт прямо сейчас
Проверить →