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

Если отключить буферизацию ответа в Nginx, чтобы передавать события или части ответа сразу, медленный клиент может затормозить не только свою загрузку: Nginx будет дольше держать соединение с приложением, а пул upstream-соединений — быстрее упираться в предел. Что именно станет узким местом первым, зависит от числа клиентов, скорости отправки и ограничений приложения; универсальной цифры нет. Ниже — разбор для Nginx Open Source 1.24.x: перед переносом настроек на другую версию сверьте директивы с её документацией.
Что меняет выключенная буферизация
По умолчанию Nginx с включённым proxy_buffering читает ответ от upstream настолько быстро, насколько позволяет его обработка, складывает данные в буферы и при необходимости — во временный файл. Клиент может получать эти данные медленнее: Nginx частично развязывает скорость приложения и скорость получателя.
При proxy_buffering off Nginx передаёт ответ клиенту синхронно с чтением от upstream. Если клиент не успевает принимать данные, запись задерживается; вслед за ней может замедлиться чтение ответа от приложения. В итоге upstream-соединение занято дольше, а если приложение держит ресурсы до завершения ответа, дольше заняты и они.
Отключённая буферизация покупает более раннюю доставку данных, но не отменяет медленного клиента. Она переносит цену этого клиента на соединение с upstream.
Это не означает, что один медленный клиент автоматически блокирует весь worker Nginx: обработка соединений событийная. Риск в другом — соединения и связанные с ними ресурсы остаются занятыми, пока передача не завершится или не сработает тайм-аут. При большом числе таких клиентов ограничения начинают складываться.
Upstream1 — сервер приложения, к которому Nginx обращается за ответом, например процесс веб-приложения или отдельный API.
Что обычно упирается первым
Порядок зависит от архитектуры. Не следует заранее считать, что проблема обязательно в сети, памяти или числе worker-процессов. Ищите первый ресурс, который перестал иметь запас.
- Пул соединений приложения. Долгие ответы удерживают соединения занятыми. Новые запросы ждут свободный слот, даже если сам Nginx ещё принимает соединения.
- Лимиты приложения. Если обработчик держит поток, задачу или другой ограниченный ресурс до конца стрима, медленная доставка растягивает его занятость. Конкретный эффект зависит от сервера приложения и его модели выполнения.
- Число соединений Nginx. Долгоживущие клиенты занимают соединения. Проверьте
worker_connectionsи лимиты файловых дескрипторов: директива задаёт предел соединений на worker, но не обещает столько же клиентских запросов сверх соединений с upstream. - Очереди и задержки. Когда приложение или его пул исчерпаны, растёт время ожидания. Клиент может увидеть задержки или обрыв по тайм-ауту, хотя Nginx ещё не перешёл к отказам.
Для SSE, генерации ответа по частям и похожих сценариев важно различать два результата: «первые байты пришли быстро» и «весь запрос завершился быстро». Стрим может улучшить первый показатель и одновременно увеличить время занятости соединения.
Как проверить, что проблема именно в буферизации
Сравните два прогона на одинаковом профиле запросов: с буферизацией и без неё. Не меняйте одновременно число workers, тайм-ауты и лимиты приложения — иначе будет неясно, что повлияло на результат.
- Зафиксируйте профиль ответа. Запишите число одновременных клиентов, размер и длительность ответа, частоту выдачи событий и долю клиентов с медленным приёмом. Проверьте: повторный прогон использует те же условия.
- Снимите метрики до переключения. Наблюдайте время ответа upstream, время до первого байта, полное время запроса, число активных соединений, ошибки и тайм-ауты. Проверьте: метрики покрывают и Nginx, и сервер приложения.
- Проведите контролируемый тест. Сравните поведение с
proxy_buffering onиproxy_buffering offна тестовом окружении. Добавьте клиентов, которые принимают данные медленнее обычного. Проверьте: видите, как меняются занятость пула и задержки. - Найдите первую исчерпанную границу. Смотрите логи приложения, очередь ожидания, открытые соединения и файловые дескрипторы. Проверьте: понятно, какой лимит достигнут раньше остальных, а не только где появился итоговый 502 или 504.
- Повторите тест с запасом и остановите его при ухудшении. Не начинайте сразу с максимальной нагрузки на рабочей системе. Проверьте: после снижения нагрузки активные соединения и задержки возвращаются к исходному уровню.
Точный порог нельзя вывести только из конфигурации Nginx: он зависит от поведения приложения, размера ответов, пропускной способности сети и лимитов ОС. Для сравнения фиксируйте не только среднее время, но и хвост распределения задержек, ошибки и длительность удержания соединений.
Границы подхода и частые ловушки
Заголовок upstream может изменить поведение
Приложение может отправить X-Accel-Buffering: no, чтобы попросить Nginx отключить буферизацию для ответа. Это работает, если Nginx не настроен игнорировать этот заголовок через proxy_ignore_headers. Поэтому проверяйте фактический ответ приложения и конфигурацию, а не только директиву в одном фрагменте конфига.
Выключать буферизацию для всего прокси не всегда нужно
Если только один маршрут отдаёт поток, настройка на уровне общего location может изменить поведение обычных ответов: буферизация полезна там, где клиенту не требуется получать данные по мере генерации. Разделяйте маршруты по назначению и проверяйте итоговую конфигурацию Nginx, включая унаследованные параметры.
Тайм-аут — не способ ускорить стрим
Увеличение тайм-аутов может помочь долгому запросу не оборваться раньше времени, но не добавляет приложению свободных соединений и не ускоряет медленного клиента. Уменьшение тайм-аутов, наоборот, может чаще обрывать допустимые долгие потоки. Настраивайте их по измеренной длительности ответа и правилам приложения, а не как замену управлению нагрузкой.
Что настроить и измерять дальше
Сначала оставьте буферизацию включённой для обычных ответов и выделите отдельный маршрут для тех, кому действительно нужна передача по частям. Затем проверьте на нагрузочном тесте, сколько одновременных потоков выдерживает приложение, и где начинает расти время ожидания.
После выкладки следите за активными соединениями Nginx, занятостью пула приложения, временем до первого байта, длительностью запросов и частотой ошибок. Если растут занятость и задержки, а скорость отправки клиенту низкая, проверьте, не удерживает ли каждый поток дефицитный ресурс приложения. Следующий шаг — измерить эти же показатели с буферизацией на конкретных маршрутах, а не отключать её глобально.
1 В документации Nginx для этого сервера часто используют термин upstream server; в статье он обозначает сторону приложения, откуда прокси получает ответ.
Логотип и фирменный стиль: Три концепции разного характера, палитра с обоснованием, проверка на читаемость в малом размере и в один цвет.
Спросить за 60 ₽Источники: Nginx 1.24: модуль ngx_http_proxy_module, Nginx 1.24: директивы ядра
Частые вопросы
Что будет первым признаком проблемы при отключённой буферизации?
Отключённая буферизация заблокирует worker Nginx?
Нужно ли ставить proxy_buffering off для SSE?
Почему конфигурация говорит buffering off, а ответ всё равно задерживается?
Можно ли увеличить тайм-аут и решить проблему под нагрузкой?
Подойдут ли эти выводы для другой версии Nginx?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.