Контроль размера запроса и этапов ожидания между клиентом, Nginx и upstream
DevOps

Лимиты запросов и таймауты Nginx: настройка без маскировки проблем

Настраиваем client_max_body_size и proxy-таймауты Nginx по реальной операции, различаем 413, 499, 502 и 504 и проверяем медленный upstream.

Содержание

Пользователь загружает фотографию и получает 413, а долгий отчёт заканчивается 504. Эти ошибки относятся к разным этапам запроса: в первом случае Nginx отклонил слишком большое тело, во втором — не дождался данных от приложения за отведённое время.

Лимит следует выбирать по функции, а не увеличивать «до большого числа». client_max_body_size ограничивает объём тела запроса. proxy_connect_timeout задаёт ожидание соединения с приложением, а proxy_send_timeout и proxy_read_timeout — допустимые паузы при передаче. Сначала соберём требования, затем настроим только нужный маршрут.

Составьте бюджет запроса

Запишите ожидаемые значения до редактирования:

  • максимальный полезный размер загрузки;
  • обычное и предельное время ответа endpoint;
  • время соединения с локальным или сетевым upstream;
  • лимит внешнего CDN/балансировщика;
  • лимит и timeout самого приложения;
  • число одновременных тяжёлых запросов.

Самый маленький предел в цепочке определит результат. Если CDN допускает меньше, изменение Nginx не поможет. Если приложение принимает 10 MiB, разрешение 1 GiB на proxy только увеличит поверхность расхода ресурсов.

Ограничьте размер тела

Если только один маршрут принимает аватары, задайте предел внутри его location. В примере Nginx допускает тело до 8 МБ и передаёт запрос локальному приложению:

location /api/avatar {
    client_max_body_size 8m;
    proxy_pass http://127.0.0.1:3000;
}

Значение — пример, а не рекомендация для любого сайта. Выберите его по реальной функции и небольшому техническому запасу. При превышении Nginx возвращает 413. У приложения должна быть понятная пользовательская ошибка и собственная проверка типа и содержимого файла: размер не заменяет валидацию.

Большое тело может буферизоваться во временный файл. Контролируйте свободное место, права временных каталогов и I/O. Не отключайте request buffering без понимания поведения upstream и повторных попыток.

Разделяйте этапы ожидания

Для обычных API-запросов задайте отдельные пределы соединения, отправки запроса и чтения ответа. Числа ниже нужны для объяснения директив и должны быть заменены после измерения вашего приложения:

location /api/ {
    proxy_pass http://127.0.0.1:3000;
    proxy_connect_timeout 3s;
    proxy_send_timeout 30s;
    proxy_read_timeout 30s;
}

Эти цифры иллюстративны. proxy_connect_timeout ограничивает установление соединения. Для локального healthy upstream оно обычно быстрое; долгий connect может означать переполненную очередь или сетевую проблему.

proxy_send_timeout действует между последовательными операциями отправки запроса к upstream, а proxy_read_timeout — между чтениями ответа. Последний не является общим дедлайном. Streaming endpoint способен передавать данные дольше, пока паузы не превышают лимит.

Таймаут клиента и таймаут upstream — разные сущности. Директивы client_header_timeout и client_body_timeout ограничивают паузы при чтении запроса от клиента. Не сокращайте их глобально без теста медленных, но законных соединений.

Интерпретируйте коды вместе с журналом

  • 413 — тело превышает допустимый размер;
  • 499 в журнале Nginx — клиент закрыл соединение до ответа;
  • 502 — Nginx не получил корректный ответ upstream или не подключился;
  • 504 — истекло ожидание upstream;
  • 408 — timeout при чтении клиентского запроса.

Код — начало расследования. 499 может означать нетерпеливого пользователя, timeout внешнего балансировщика или очень медленное приложение. 504 после роста proxy_read_timeout может лишь наступить позже.

Добавьте измеримые поля

Чтобы понять, на каком этапе прошло время, добавьте в контекст http отдельный формат access log. Он запишет полное время запроса и три измерения взаимодействия с upstream:

log_format timing '$remote_addr "$request" status=$status '
                  'rt=$request_time uct=$upstream_connect_time '
                  'uht=$upstream_header_time urt=$upstream_response_time '
                  'us=$upstream_status';

Включите его для нужного server и соберите достаточный период. $request_time охватывает взаимодействие Nginx с клиентом, а upstream-поля помогают отделить connect, получение заголовка и полный ответ приложения.

Не добавляйте request body, Authorization или cookies в журнал. Query string тоже может содержать секреты — это нужно учитывать при выборе $request.

Как исправлять долгую операцию

Если отчёт действительно формируется минуты, HTTP-запрос часто не должен ждать всё время. Приложение может поставить задачу в очередь, вернуть идентификатор и предоставить статус или готовый файл позже. Это освобождает workers и делает поведение управляемым.

Для обычного endpoint проверьте запрос базы, внешние API, pool соединений, блокировки и лимит workers. Увеличивайте timeout только после подтверждения, что операция законна и ресурсы выдерживают параллелизм.

Проверка и откат

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

sudo nginx -t
sudo systemctl reload nginx
curl -I https://example.com/api/health
sudo tail -n 100 /var/log/nginx/error.log

Тест загрузки выполняйте безопасным файлом около границы: один ниже и один выше лимита. Для timeout используйте контролируемый тестовый endpoint, а не задержку production-пользователей. Сравните журналы Nginx и приложения.

При ухудшении верните предыдущий блок, выполните nginx -t и reload. Для общей схемы смотрите reverse proxy Nginx и диагностику по логам.

Наблюдение после изменения

Сравните период до и после: долю 413/499/502/504, p95 времени ответа, число активных соединений, очередь и память upstream. Среднее время скрывает редкие, но тяжёлые запросы. Один успешный curl подтверждает маршрут, но не устойчивость при параллельной загрузке.

Задайте оповещение по росту ошибок и насыщению, а не по единичному коду. Если предел нужен только административной операции, отделите endpoint и доступ к нему. Это не позволит большой timeout или upload стать значением по умолчанию для всего публичного API.

Первоисточники

Рекламное местоВаша компания здесьРазместить рекламу

Самопроверка

Проверьте, что материал усвоен

Ответьте на все вопросы. Результат сохранится только в этом браузере и будет учтён в статистике прочитанных материалов.

01Где лучше увеличить лимит загрузки для одного upload endpoint?
02Что регулирует proxy_connect_timeout?
03Что делать при стабильных 504 после тяжёлого отчёта?

Разбираем коротко

Частые вопросы

Почему увеличение proxy_read_timeout не ускоряет приложение?

Таймаут лишь позволяет Nginx дольше ждать данные от upstream. Он не уменьшает время вычисления и может удерживать больше соединений; сначала найдите медленный запрос по логам и метрикам приложения.

Что означает ошибка 413 Request Entity Too Large?

Тело запроса превышает client_max_body_size на одном из уровней. Значение нужно согласовать с приложением, внешним proxy и бизнес-ограничением, а не снимать лимит глобально.

Является ли proxy_read_timeout полным временем выполнения запроса?

Нет. Nginx измеряет паузу между последовательными операциями чтения ответа upstream. Если upstream периодически передаёт данные, общее соединение может жить дольше этого значения.