Upstream timeout в Nginx: где искать причину
АйТи Фреш
Серверы и инфраструктура

Как найти причину таймаута между Nginx и приложением

Автор: , директор ООО «АйТи-Фреш» · · ~11 мин чтения
Поток запроса задержался на этапе ожидания ответа upstream в Nginx
Сначала найдите этап ожидания

`upstream timed out` означает, что Nginx не получил очередные данные от upstream в пределах настроенного интервала. Это еще не диагноз: задержку может создавать приложение, база, сеть или неверно выбранный таймаут. Я начинаю с журнала и замеров, а конфигурацию меняю только после того, как понимаю, где именно теряется время.

Что означает upstream timed out в журнале Nginx

Сообщение upstream timed out говорит о превышении времени ожидания ответа от upstream — сервера, к которому Nginx передал запрос. Уточнение после while важно: connecting to upstream указывает на этап соединения, while reading response header from upstream — на ожидание заголовков ответа, а while reading upstream может относиться к чтению тела. Это разные участки пути. Поэтому одной строкой «увеличьте таймаут» проблему не диагностируют. Nginx здесь работает как обратный прокси и передает запрос приложению; запись в журнале описывает, на каком этапе он перестал ждать. Номер системной ошибки в скобках зависит от ОС, поэтому не превращайте одно значение вроде 110 в универсальный код причины.

Сначала сопоставьте время ошибки с access log и журналом приложения. Проверьте $request_time, $upstream_connect_time, $upstream_header_time и $upstream_response_time, если эти поля включены в формат журнала. Сравните их на нескольких проблемных запросах: долгое подключение, долгое ожидание первого заголовка и долгое чтение уже начавшегося ответа — не одно и то же. Убедитесь, что смотрите правильный виртуальный хост и правильный upstream, а системное время на узлах синхронизировано. Если ошибка редкая, сохраните несколько примеров вместе с URI без секретных параметров, временем и статусом. Один длинный запрос не доказывает, что медленным стало всё приложение. Перезагрузка может убрать симптом на минуту; диагностикой она от этого не становится.

Не считайте upstream timed out тождественным HTTP 504 во всех случаях: клиентский ответ зависит от конфигурации и от того, успел ли Nginx отправить заголовки. Посмотрите статус, завершение запроса и upstream-поля рядом, а не только одну строку error log. Если проблема возникает у одного маршрута, сравните его с соседним при той же нагрузке. Если одновременно замедлились разные маршруты, проверьте общие зависимости: пул соединений, базу и сетевой путь. Так расследование остается привязанным к наблюдаемым данным, а не к догадке по тексту ошибки.

`client_max_body_size` ограничивает размер тела запроса, а не ожидание ответа от upstream.
Схема этапов запроса и мест, где Nginx ожидает upstream
Разделите этапы ожидания

Какие таймауты менять и где их задавать

У директив разные обязанности. proxy_connect_timeout ограничивает установление соединения с проксируемым сервером. proxy_send_timeout задает интервал между операциями записи запроса в upstream. proxy_read_timeout — интервал между операциями чтения ответа от upstream, а не максимальную длительность всего ответа. Для этих proxy-директив документация NGINX указывает значение по умолчанию 60s; у send_timeout отдельный смысл — ожидание между операциями записи ответа клиенту. Эти параметры действуют в контекстах http, server и location, но менять их лучше на минимальном подходящем уровне. Не копируйте числа из чужого конфига: у долгого экспорта и обычного API разные требования, а общий таймаут может затронуть несвязанные маршруты.

Для медленного ответа сначала выясните, что именно долго: подключение, появление заголовков или дальнейшая передача данных. Затем задайте целевой интервал в location конкретного маршрута, проверьте конфигурацию командой nginx -t и применяйте изменение штатным способом для вашей системы. Сверьте результат на тех же запросах и следите за числом одновременно ожидающих операций. Таймаут — не педаль ускорения: нажал сильнее, приложение быстрее не стало. Более длинное ожидание не ускорит приложение; оно только позволит соединению ждать дольше и может увеличить занятые ресурсы при всплеске запросов. Я не назначаю одно «правильное» значение в секундах без профиля нагрузки и требований приложения. Если причина — блокировка базы или внешний сервис, лечить это таймаутом всё равно что растянуть очередь и объявить её производительнее.

Сверьте реальный proxy_pass и выбранный location: приоритеты location и передача URI влияют на то, какой обработчик получит запрос. Не публикуйте в тикетах полные заголовки авторизации, cookie и тела запросов. Для сравнения достаточно времени, безопасного идентификатора, статуса и маршрута без чувствительных параметров. Если access log пока не содержит upstream-времена, добавляйте их осознанно в формат журнала и проверьте, что формат совместим с вашей системой сбора логов.

Сначала измерьте интервал и найдите его причину; затем меняйте параметр в нужном `location`.
Сопоставление директив таймаута Nginx с этапами запроса
У каждой директивы свой этап

Как отделить задержку приложения от сети и базы

Проведите запрос с узла Nginx к тому же адресу upstream и зафиксируйте DNS-разрешение, время подключения и время до первого байта. Это проверит маршрут, но не заменит наблюдение за реальным запросом: приложение может зависеть от конкретных данных, очереди задач или внешнего API. На стороне приложения сопоставьте идентификатор запроса, если он передается безопасно, с собственными журналами и временем выполнения обработчика. На стороне системы посмотрите CPU, память, дисковый ввод-вывод, очереди и число открытых соединений. Метрики наподобие http_request_duration_seconds не возникают автоматически от установки Prometheus: их должен публиковать инструментируемый сервис или экспортер, а название и метки нужно знать для конкретной системы.

Если приложение использует PostgreSQL, проверяйте активные запросы и блокировки. Представление pg_locks показывает сведения о текущих удерживаемых и ожидающих блокировках; сам по себе запрос SELECT * FROM pg_locks не объясняет, кто кого блокирует и почему. Сопоставьте PID, состояние сессии и длительность запроса с журналом приложения, а при необходимости разберите план и транзакции вместе с ответственным за базу. strace -p PID -c суммирует системные вызовы процесса, но не профилирует SQL и не раскрывает «медленный запрос» напрямую. На рабочем сервисе сначала оцените влияние диагностики и права доступа. Не меняйте уровень изоляции транзакций наугад: это может поменять поведение приложения и привести к новым ошибкам.

Для proxy-параметров NGINX допускает суффиксы времени, например s и ms; задавайте значение явно и проверьте загруженную конфигурацию после изменения. Учтите, что директива на более узком уровне конфигурации может переопределить унаследованную настройку. Поэтому проверяйте именно эффективный файл и подключаемые фрагменты, а не только один знакомый nginx.conf. Записывайте исходное значение и причину изменения, чтобы откат не превратился в археологию по истории терминала.

Метрика полезна, только если известны источник, единицы измерения и метки.
Если по журналам не видно, где теряется время, я помогу разобрать цепочку Nginx — приложение — база и подобрать изменения по измерениям. Обслуживание сервера — от 7 000 ₽/мес. Обсудить задачу

Keepalive и повторная отправка: настройки с оговорками

Директива keepalive в блоке upstream задает кэш неактивных соединений к upstream на каждый worker-процесс. Это не общий лимит всех соединений к приложению и не команда «держать ровно столько соединений». Для HTTP-переиспользования важны версия NGINX и заголовок Connection: в актуальной документации поведение HTTP keepalive включено по умолчанию начиная с NGINX 1.29.7; для старых версий обычно задают proxy_http_version 1.1 и очищают заголовок Connection. Значит, совет «добавьте keepalive 32; и всё заработает» без проверки версии и контекста неполон. Значение выбирают с учетом числа workers, нагрузки и того, сколько соединений способен обслужить сам backend.

proxy_next_upstream timeout; позволяет считать таймаут неудачной попыткой и при соблюдении условий попробовать следующий сервер. Но NGINX может передать запрос дальше, только пока еще не начал отправлять ответ клиенту; уже отправленное тело запроса тоже ограничивает повтор. Особенно осторожно относитесь к POST и другим операциям с побочными эффектами: повтор способен создать дубликат операции, а резервный сервер может не иметь актуального состояния. Не включайте ретраи как универсальную страховку. Проверьте семантику конкретного метода, идемпотентность обработчика, состояние репликации и поведение при частичном ответе. Директива proxy_next_upstream_tries ограничивает число попыток; значение 0 означает, что такого ограничения директивой нет. Настроенный retry — это политика обработки ошибки, а не автоматическая гарантия отказоустойчивости.

Чтобы найти блокирующую сессию PostgreSQL, полезно связать pg_locks с pg_stat_activity и проверить поля ожидания и текст выполняемого запроса с учетом прав доступа. Не завершайте backend-процесс, пока не оценили транзакцию и последствия отмены. Блокировка может быть нормальной частью конкурентной работы, а не неисправностью сама по себе. Для медленного SQL важны план выполнения, объем данных и статистика; изменение индексов без плана тоже не универсальный рецепт.

Повтор POST может повторить действие. Сначала проверьте идемпотентность.

Безопасная проверка изменений и наблюдение

Обычный error_log ... debug не включается наугад в рабочей среде. Для debug-журнала NGINX должен быть собран с поддержкой --with-debug; проверьте параметры сборки через nginx -V и инструкцию поставщика пакета. Включайте подробный журнал коротким окном, с ограниченным охватом и контролем объема: он быстро разрастается и содержит технические детали запросов. Уровень debug не гарантирует, что в любом пакете появятся ожидаемые записи. Путь /var/log/nginx/error.log также не универсален: журнал может идти в другой файл, syslog или стандартный поток контейнера. Сначала выясните фактическую конфигурацию error_log, права и ротацию. Затем проверьте синтаксис и примените конфиг способом, принятым на этом сервере.

Проверяйте исправление на контролируемом трафике и сравнивайте одинаковые показатели до и после: время соединения, время до заголовка, полное время upstream, долю ошибок и ресурсную нагрузку. wrk и ab могут генерировать нагрузку, но сами по себе не создают реалистичный профиль: учитывайте сценарии, число одновременных клиентов, прогрев, кэш и безопасную тестовую среду. Не запускайте агрессивный тест на чужом или нагруженном сервисе без согласования окна и лимитов. Оставьте наблюдение за ошибками и не отключайте оповещения только потому, что график однажды выровнялся. Если таймауты вернулись, ищите, что изменилось: поток запросов, база, внешний вызов или конфигурация upstream. Успешная проверка — повторяемый результат под ожидаемой нагрузкой, а не красивое число из одного прогона.

В HTTP keepalive повторно используется TCP-соединение, когда протокол, заголовки и приложение допускают такое поведение. Переиспользование снижает стоимость новых установлений соединений, но не делает запрос быстрее, если обработчик ждет базу. Кэш keepalive учитывается на worker; умножьте выбранный размер на число процессов и сопоставьте результат с лимитами backend. Также проверьте таймаут неактивности на стороне приложения: если оно закрывает соединение раньше, Nginx может получить закрытый сокет и установить новое.

Нагрузочный тест проводите только на разрешенной тестовой или контролируемой среде.
Последовательность проверки и исправления upstream timeout
Меняйте конфиг после замера

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

Что означает `upstream timed out`?

Nginx не получил очередные данные от проксируемого сервера за заданный интервал. Уточнение `while` показывает этап, на котором истекло ожидание.

Какой таймаут отвечает за ожидание ответа?

Обычно проверяют `proxy_read_timeout`: это максимальная пауза между чтениями от upstream, а не лимит полной длительности ответа.

Нужно ли всегда включать debug-лог?

Нет. Для него нужна сборка NGINX с `--with-debug`; подробное логирование включают ограниченно и проверяют поддержку в установленном пакете.

Поможет ли `keepalive 32` от таймаутов?

Сам по себе параметр не исправит медленный обработчик. Это кэш неактивных соединений; проверьте версию NGINX, HTTP-настройки и возможности backend.

Можно ли повторять запрос на резервный сервер после timeout?

Только если повтор безопасен и запрос еще можно передать дальше. Для операций с побочными эффектами сначала проверьте идемпотентность и состояние данных.

Столкнулись с похожей задачей? Обращайтесь — решим

Если у вас происходит что-то из описанного в этой статье — или любая другая проблема с ИТ-инфраструктурой, — обращайтесь в любое время. Мои специалисты и я лично разберём ситуацию, найдём настоящую причину и доведём до решения.

Возьмёмся и за разовую задачу, и за постоянное обслуживание. Первичная консультация — бесплатно и без обязательств.

📞 +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

Источники

© ООО «АйТи-Фреш» · Москва · Все статьи