Разбор инцидента в Nginx: почему 502 растёт под нагрузкой
Сервис начинает отдавать 502 не потому, что Nginx «сломался». Под нагрузкой прокси может не успеть подключиться к приложению, получить от него заголовки или вернуть ответ из-за переполненного пула соединений.

Триста одновременных запросов могут превратить исправный Nginx в источник лавины 502: часть соединений не доходит до приложения, часть закрывается до отправки заголовков, а очередь на стороне upstream переполняется. В этом разборе — как отличить эти сценарии по логам, что измерить до изменения конфигурации и почему увеличение таймаутов часто только прячет проблему.
Что именно означает 502 в Nginx
Код 502 Bad Gateway означает, что Nginx выступал прокси и не получил корректный ответ от upstream[1] — например, от PHP-FPM, Gunicorn, uWSGI, Node.js или отдельного HTTP-сервиса.
Это не один конкретный сбой. Nginx может:
- не установить TCP-соединение с приложением;
- подключиться, но получить разрыв до HTTP-заголовков;
- получить повреждённые или неполные заголовки;
- обратиться к upstream, который исчерпал рабочие процессы или соединения;
- попасть в ситуацию, когда приложение живо, но не принимает новые запросы.
Поэтому строка в access log с кодом 502 — только симптом. Причину ищут в error log и в метриках самого приложения.
502 под нагрузкой — это обычно не «слишком маленький таймаут», а разрыв контракта между прокси и upstream: приложение не успевает принять, обработать или корректно завершить запрос.
Как развивался инцидент
Представим типичный стек: Nginx 1.25.x или 1.26.x, приложение за ним и отдельный процесс-менеджер. При обычном трафике ответ занимает 80–150 мс. После роста параллельности приложение начинает занимать все worker-процессы. Новые запросы остаются в очереди, а часть клиентов получает 502.
Порядок событий обычно выглядит так:
- Nginx принимает клиентское соединение и передаёт запрос upstream.
- Приложение не может немедленно выделить worker или поток.
- TCP-очередь либо очередь приложения заполняется.
- Соединение закрывается, отклоняется или не получает заголовки вовремя.
- Nginx записывает ошибку upstream и возвращает клиенту 502 или 504.
Разница между кодами важна. Если upstream не ответил за допустимое время чтения, чаще появляется 504. Если соединение было отклонено, закрыто или ответ оказался некорректным, вы увидите 502. На практике один перегруженный backend способен выдавать оба кода одновременно.
Сначала смотрите error log, а не таймауты
В error log ищите точную формулировку после слова upstream. Она сужает поиск до нескольких сценариев.
| Фрагмент ошибки | Что вероятнее всего происходит | Что проверить |
|---|---|---|
connect() failed (111: Connection refused) | Порт приложения не принимает новые соединения или процесс недоступен | Состояние процесса, listen-порт, backlog, лимиты файловых дескрипторов |
upstream prematurely closed connection | Backend закрыл соединение до полного ответа | Падения worker, исключения приложения, OOM, таймауты в самом backend |
no live upstreams | Nginx не видит доступного сервера в upstream-группе | Health-check логику, DNS, доступность всех адресов |
upstream timed out | Ответ или подключение заняли дольше заданного времени | Медленные запросы, очередь, proxy_read_timeout, базу данных |
upstream sent invalid header | Приложение вернуло невалидные HTTP-заголовки | Фреймворк, промежуточный прокси, размер и формат заголовков |
Одновременно сопоставьте время ошибки в трёх местах: access log Nginx, error log и журнал приложения. Если в Nginx есть 502, а приложение в ту же секунду перезапустилось, причина почти наверняка не в директиве прокси.
Что ломается первым под нагрузкой
Очередь и число workers
У приложения есть конечное число одновременно обрабатываемых запросов. Если PHP-FPM, Gunicorn или другой сервер исчерпал workers, новые соединения ждут. Увеличение workers без проверки CPU, памяти и базы данных может ухудшить ситуацию: запросов станет больше, но каждый будет завершаться медленнее.
Проверяйте не только среднее время ответа. Нужны p95 и p99, длина очереди, число активных workers, ошибки OOM и доля запросов, завершившихся 5xx.
Соединения и лимиты операционной системы
Под нагрузкой Nginx и backend открывают больше файловых дескрипторов. Если лимит исчерпан, в журнале появляются ошибки вроде too many open files. Отдельно проверяйте очередь прослушиваемого сокета и число соединений в состояниях SYN-RECV, ESTABLISHED и TIME-WAIT.
Директива worker_connections ограничивает число соединений на worker Nginx, но это не равно числу запросов к приложению. При проксировании одно клиентское соединение и одно соединение к upstream могут занимать разные ресурсы.
Медленная зависимость внутри приложения
Backend может быть доступен и при этом не успевать: запрос ждёт базу данных, внешний API, файловое хранилище или блокировку. В error log Nginx это часто выглядит как таймаут upstream, хотя первопричина находится глубже.
Если 502 появляется только на одном URL, сравните его с быстрым health endpoint. Если health endpoint стабилен, а бизнес-запросы падают, не увеличивайте таймаут вслепую: найдите медленную операцию внутри обработчика.
Какие изменения действительно помогают
Конфигурацию ниже можно использовать как ориентир для Nginx 1.25.x и 1.26.x. Значения не универсальны: время чтения должно соответствовать реальному SLA приложения, а не быть «побольше».
upstream app_backend {
server 127.0.0.1:8000;
keepalive 32;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://app_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 2s;
proxy_read_timeout 30s;
proxy_send_timeout 30s;
}
}
Параметр keepalive 32 оставляет пул неактивных соединений к upstream. Это может снизить стоимость повторных TCP-соединений, но не увеличивает число workers приложения и не заменяет контроль нагрузки. Слишком большой пул способен занять лишние ресурсы backend.
proxy_connect_timeout ограничивает установление соединения, а proxy_read_timeout — паузу между чтениями ответа. Последний не ограничивает весь запрос целиком: если приложение регулярно отправляет данные, общий запрос может длиться дольше. Для длинных операций нужен отдельный SLA и, возможно, фоновые задачи, а не бесконечный таймаут.
Где подход ломается
Есть несколько опасных исправлений, которые убирают симптом на короткое время.
- Поднять таймаут с 30 до 300 секунд. Очередь станет длиннее, соединения будут дольше занимать память, а отказ произойдёт позже и массовее.
- Без расчёта увеличить число workers. Если узкое место — база данных или CPU, workers начнут конкурировать за тот же ресурс.
- Включить повтор запроса на другой upstream. Для POST и других неидемпотентных операций это может создать дубль заказа или платежа. Повтор допустим только при явно проверенной идемпотентности.
- Скрыть 502 страницей ошибки. Клиенту станет понятнее сообщение, но причина и нагрузка никуда не исчезнут.
Отдельная тема — кэширование и инвалидация кэша. Здесь важно не смешивать их с диагностикой транспортной ошибки: кэш может снизить нагрузку, но не объясняет, почему upstream закрыл соединение.
Как измерить исправление
Сравнивайте до и после при одинаковом сценарии: один и тот же URL, размер данных, число виртуальных пользователей и длительность теста. Зафиксируйте версию конфигурации и приложения, чтобы результат можно было повторить.
- доля 2xx, 4xx, 502 и 504;
- p50, p95 и p99 времени ответа;
- число активных и занятых workers приложения;
- CPU, RSS, swap и события OOM;
- количество открытых файлов и соединений;
- время запросов к базе и внешним сервисам.
Полезно добавить в access log время обработки запроса и адрес upstream. В Nginx для этого применяют переменные вроде $request_time и $upstream_response_time. Если первое значение велико, а второе пусто, запрос мог не дойти до upstream. Если второе велико, задержка возникла уже после подключения к приложению.
Что делать дальше
Сначала соберите десять–пятнадцать минут логов вокруг пика и сгруппируйте 502 по тексту ошибки, URL и upstream. Затем отдельно проверьте очередь приложения, лимиты файловых дескрипторов и медленные зависимости. После изменения конфигурации повторите нагрузочный тест и оставьте алерт не только на долю 502, но и на p95/p99, длину очереди и перезапуски backend.
[1] Upstream — сервер или группа серверов, куда Nginx передаёт запрос клиента. В этой статье под ним подразумевается приложение за обратным прокси.
Тест и проверочная: Быстрые ответы с объяснением, почему остальные варианты неверны
Спросить за 10 ₽Источники: Nginx ngx_http_proxy_module: proxy_pass, таймауты и заголовки, Nginx ngx_http_upstream_module: upstream и keepalive
Частые вопросы
Можно ли исправить 502 увеличением proxy_read_timeout?
Почему Nginx отдаёт 502, если приложение работает?
Чем 502 отличается от 504?
Нужно ли увеличивать число workers приложения?
Что делать, если после исправления 502 снова появляется на пике?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.