ZIM-НИЙ SAAALEЗимние скидки: до −50% на старт и −20% на продление
до 31.01.2026 Подробнее
Выберите продукт

HTTP/2 in Nginx: multiplexing, stream priorities, and where performance is lost

HTTP/2 обещает ускорение за счёт multiplexing и приоритетов потоков, но на практике всё упирается в TCP head-of-line blocking, TLS/ALPN, лимиты Nginx и TTFB приложения. Разбираем механику и тюнинг, который даёт измеримый эффект.
HTTP/2 in Nginx: multiplexing, stream priorities, and where performance is lost

Зачем разбираться в HTTP/2, если «оно само быстрее»

HTTP/2 (h2) часто включают по принципу «галочка ради performance»: один TCP‑коннект, multiplexing, сжатые заголовки, браузер счастлив. На реальных проектах всё сложнее: ускорение есть не всегда, а иногда проявляются новые узкие места — от очередей в TCP до неверных ожиданий от приоритизации потоков.

Ниже разберём, что именно делает HTTP/2 в Nginx быстрее (и что он не делает), как работает multiplexing, где возникает head of line blocking (HOL), почему stream priority почти не спасает, и что реально тюнить, чтобы увидеть улучшение в метриках, а не «на глаз».

Короткая модель: что меняется между HTTP/1.1 и HTTP/2

Чтобы правильно читать графики и логи, полезно держать в голове две упрощённые схемы.

HTTP/1.1

Типичная картина в браузере: много параллельных TCP‑соединений к одному хосту (часто до 6 на домен), в каждом — запрос/ответ по очереди. Есть keepalive, есть pipelining (на практике почти не используется браузерами), поэтому параллелизм достигается в основном количеством соединений.

Плюс: потеря пакета тормозит только ответы внутри конкретного соединения. Минус: много соединений — это больше накладных расходов на TLS, congestion control, переключение контекста и буферы.

HTTP/2

Обычно один TCP‑коннект на origin (в реальности может быть больше, но идея такая). Внутри — множество streams (логических потоков запросов/ответов). Данные режутся на frames и перемежаются. Это и есть multiplexing: пока один ресурс «думает», другой может передаваться в том же соединении, а браузер меньше упирается в очереди.

Плюс: меньше соединений, лучше утилизация канала, меньше накладных расходов на TLS и «медленный старт» TCP. Минус: появляется системная цена ошибки — если в единственном TCP‑коннекте теряется сегмент, ожидание ретрансмита может тормозить всё сразу. Это главный источник HOL в HTTP/2.

Multiplexing в деталях: почему один коннект бывает лучше шести

Практическая выгода multiplexing — не магическая «ускорялка», а более эффективное использование одного TCP окна и одного состояния congestion control. Для страниц с большим количеством мелких ресурсов (CSS/JS/иконки/шрифты) HTTP/2 часто выигрывает по времени до рендера: браузеру проще начать получать понемногу «всего важного» и не упираться в очередь одного соединения.

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

Отдельно полезно помнить, что «один коннект» меняет профиль нагрузки: меньше TLS‑рукопожатий и меньше соединений в целом, но выше требования к стабильности этого единственного канала и к предсказуемости отдачи контента.

Как Nginx отдаёт ответы в HTTP/2

Nginx режет тело ответа на HTTP/2 фреймы и планирует отправку по потокам. Браузер держит свои лимиты на количество одновременных потоков, а сервер объявляет свои. В Nginx это управляется параметрами вроде http2_max_concurrent_streams и связанными лимитами на заголовки и буферы.

Важно: если ограничить concurrent streams слишком низко — вы сами себе обрежете пользу multiplexing. Если слишком высоко — усилите конкуренцию за CPU/память/диск и можете «забить» канал мелкими кусками так, что критичные ресурсы начнут приезжать позже.

Схема сравнения HTTP/1.1 и HTTP/2: несколько соединений против multiplexing в одном

Stream priority: почему приоритеты не работают как «волшебная кнопка»

Спецификация HTTP/2 предусматривает механизм приоритизации: зависимости потоков, веса, перестройка дерева. Браузер может сказать: «CSS важнее картинок, а этот JS зависит от CSS».

На практике stream priority — одна из самых неоднозначных тем:

  1. Браузеры по‑разному выставляют приоритеты и меняли алгоритмы годами.
  2. Серверы и прокси по‑разному их учитывают. Nginx исторически не стремится к «идеальному» планировщику по дереву зависимостей.
  3. Даже если приоритеты учтены, они не отменяют физику TCP: потери, переполненные буферы и конкуренция за ресурсы на бэкенде ломают ожидания.

Ментальная модель: приоритеты в HTTP/2 — это подсказка планировщику «что отправлять раньше», но не гарантия. Гарантии ломаются о congestion control, потери и реальную очередь на стороне приложения.

Что делать вместо «веры в приоритеты»

Если цель — измеримая performance, чаще всего эффективнее работать с базовыми рычагами:

  • уменьшать количество критичных запросов (разумный бандлинг, code splitting, меньше шрифтов);
  • обеспечивать быстрый TTFB (кеширование, оптимизация бэкенда, микрокеш на edge);
  • настраивать кеш и компрессию так, чтобы статика не ездила повторно;
  • управлять критическим путём на фронтенде (например, rel=preload и порядок подключения CSS).

Приоритеты в HTTP/2 — это бонус, который может сработать при хорошем базовом состоянии системы, но редко является главным инструментом ускорения.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Head of line blocking в HTTP/2: где именно происходит блокировка

Важно различать два HOL‑эффекта.

HOL в HTTP/1.1 (уровень приложения)

Когда запросы в одном соединении идут последовательно, большой ответ может задерживать маленький даже при идеальной сети. Это «прикладной» HOL. Он частично устраняется multiplexing в HTTP/2.

HOL в HTTP/2 (уровень TCP)

В HTTP/2 много потоков делят один TCP. TCP обеспечивает упорядоченную доставку байтов. Если потерялся один сегмент, стек ждёт его ретрансмит, и пока «дыра» не закрыта, последующие байты не отдаются приложению — даже если они относятся к другому stream. Это классический head of line blocking в HTTP/2.

Симптом: на нестабильной сети (мобильная связь, Wi‑Fi, дальние регионы) один «плохой» поток может просадить загрузку всей страницы, хотя по логике multiplexing всё должно ехать параллельно.

Почему это важно именно для Nginx

Nginx часто стоит на границе (edge) и обслуживает тысячи клиентов. Если у заметной части аудитории высокие RTT или потери, вы можете увидеть, что HTTP/2 даёт меньше выигрыша, чем ожидали, или даже ухудшает хвосты задержек (p95/p99) по сравнению с HTTP/1.1 с несколькими соединениями.

Это не «проблема Nginx», это свойство TCP. Поэтому многие смотрят в сторону HTTP/3 (QUIC), где HOL на транспортном уровне решён иначе. Но в рамках HTTP/2 важно понимать, почему именно графики могут выглядеть «контринтуитивно».

Что нужно включить в Nginx для HTTP/2 (и что проверить)

HTTP/2 в браузерном вебе почти всегда работает поверх TLS. Формально существует h2c (HTTP/2 без TLS), но браузеры обычно его не используют. Поэтому базовые проверки сводятся к TLS/ALPN и корректному listen.

Базовый пример server-блока

server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate /etc/ssl/example/fullchain.pem;
    ssl_certificate_key /etc/ssl/example/privkey.pem;

    location / {
        root /var/www/example;
        try_files $uri $uri/ =404;
    }
}

Критично: наличие http2 в директиве listen для 443 и корректный TLS. Если ALPN не согласован, клиент уйдёт на HTTP/1.1.

Если вы ещё не закрыли TLS «как положено», лучше начать с нормального сертификата и автоматизации продления: это напрямую влияет на конверсию HTTP/2 через ALPN и на стабильность HTTPS в целом. Для публичных сайтов имеет смысл использовать проверенные SSL-сертификаты.

Параметры, которые чаще всего имеют смысл

Точные значения зависят от профиля нагрузки, но как чек‑лист:

  • http2_max_concurrent_streams — сколько потоков разрешать одному соединению. Слишком низко: недоиспользуете multiplexing. Слишком высоко: риск конкуренции и роста памяти.
  • http2_recv_buffer_size — буфер приёма. Может влиять на поведение при больших телах и медленных клиентах.
  • keepalive_timeout — влияет на удержание соединения и переиспользование. Для HTTPS это часто важнее, чем кажется.
  • ssl_session_cache и ssl_session_tickets — ускоряют повторные подключения (не про HTTP/2 напрямую, но про общую latency).

Совет из практики: сначала убедитесь, что нет очевидных проблем уровня TLS и keepalive, и только потом лезьте в тонкие HTTP/2‑лимиты. Часто «медленно» из‑за TTFB от приложения или из‑за неверной кеш‑политики статики.

Performance: где HTTP/2 реально ускоряет, а где нет

Ниже — типовые случаи, где эффект HTTP/2 в Nginx обычно заметен, и где его почти не будет.

Часто ускоряет

  • Много мелких статичных файлов на одной странице (иконки, чанки JS, CSS, webfont).
  • Высокая доля повторных визитов (соединение живёт, TLS‑сессии переиспользуются).
  • Сервинг статики напрямую Nginx или из кеша (минимальный TTFB).

Часто не ускоряет (или ускоряет среднее, но не хвосты)

  • Один-два больших файла (например, крупные архивы) — там важнее пропускная способность и I/O.
  • Медленный upstream и динамика без кеша — упираетесь в приложение, а не в протокол.
  • Плохие сети у значимой доли аудитории — HOL на TCP может съесть преимущества.

Отдельная зона «ожидание vs реальность» — попытки заменить архитектурные решения приоритетами/настройками протокола. Если критический CSS генерируется долго, а API отдаёт HTML с задержкой, протокол уже вторичен.

Как диагностировать: что измерять, чтобы не спорить «на вкус»

Самый частый провал при внедрении HTTP/2 — отсутствие нормального сравнения «до/после». Нужны метрики и воспроизводимый тест.

1) Подтвердить, что реально используется HTTP/2

Проверьте протокол на клиенте и на сервере. На стороне Nginx удобно добавить в лог переменную протокола.

log_format main '$remote_addr - $host [$time_local] '
                '"$request" $status $body_bytes_sent '
                'proto=$server_protocol '
                'rt=$request_time urt=$upstream_response_time';

Переменная $server_protocol покажет HTTP/2.0 для h2. Дальше можно сегментировать статистику по протоколу и сравнить latency на одинаковых ручках.

2) Сравнивать p50/p95/p99, а не только среднее

HTTP/2 может улучшить медиану, но ухудшить хвосты на проблемных сетях из‑за HOL. Если вы смотрите только среднее, легко принять неверное решение.

3) Разделять статику и динамику

Если статика уходит быстро, а динамика медленная, итоговая «скорость сайта» определяется TTFB и очередями в приложении. В таком случае HTTP/2 даст косметический эффект, а настоящий выигрыш обеспечат кеширование, оптимизация базы или микрокеш на edge.

Про то, как протокол и кеш‑стратегии влияют на отдачу диапазонами и прокси‑кеш, полезно держать под рукой разбор про HTTP Range и кеширование в Nginx/Apache.

Фрагмент конфигурации Nginx и дашборд с метриками p95/p99 для сравнения протоколов

Практические рекомендации: что улучшать вокруг HTTP/2 в Nginx

Оптимизируйте количество запросов и размер критического пути

Multiplexing помогает, но не отменяет стоимость каждого запроса: заголовки, обработка, планирование, возможные промахи кеша. На фронтенде это означает: меньше критичных CSS, аккуратнее с количеством шрифтов, разумный code splitting.

Следите за кешированием статики и заголовками

Для performance часто важнее правильный Cache-Control и неизменяемые ассеты, чем тонкая настройка http2_max_concurrent_streams. Уменьшите повторные загрузки — и вы уменьшите влияние любой транспортной сложности, включая HOL.

Не забывайте про компрессию и CPU

HTTP/2 включает HPACK для заголовков, но это не замена gzip/brotli для тела ответа. Если вы включаете тяжёлую компрессию на лету, оцените CPU. На высоком RPS именно CPU на компрессию может съесть выгоду от HTTP/2.

Проверьте, нет ли «самострела» в лимитах

Иногда включают строгие лимиты на заголовки и буферы, а потом ловят странные ошибки у части клиентов. У HTTP/2 заголовки (особенно с cookies) могут быть объёмными, а запросов много. Проверьте значения large_client_header_buffers, client_header_buffer_size и связанные лимиты в контексте вашего приложения.

FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

FAQ для админов: частые вопросы про HTTP/2 в Nginx

Нужно ли включать HTTP/2 для API?

Часто да, если клиенты — браузеры или мобильные приложения с большим количеством запросов. Но если API — это редкие запросы «один большой JSON» и вы упираетесь во время ответа приложения, разница будет небольшой. Важно измерять.

Можно ли «починить» head of line blocking настройками Nginx?

Полностью нет: HOL в HTTP/2 происходит на уровне TCP. Можно лишь уменьшить вероятность проблем: снизить размеры ответов, уменьшить конкуренцию больших и маленьких ресурсов, настроить кеширование и быстрее завершать потоки, чтобы соединение не «зависало» на долгих передачах.

Почему в браузере всё равно бывает больше одного соединения?

Браузер может открыть дополнительные соединения при определённых условиях: разные домены, разные политики, ограничения реализации. Это нормально. HTTP/2 не гарантирует «ровно одно соединение», он меняет модель внутри соединения.

Итоги: как получать пользу от HTTP/2 в Nginx без разочарований

HTTP/2 в Nginx — хороший инструмент для ускорения страниц с множеством ресурсов за счёт multiplexing и более эффективного использования одного соединения. Но ожидать, что stream priority автоматически расставит всё «как надо», не стоит, а HOL на TCP может проявиться в хвостовых задержках на проблемных сетях.

Практический подход: включить HTTP/2 корректно, подтвердить протокол в логах, измерять p95/p99, разделять статику и динамику, и в первую очередь улучшать TTFB и кеш‑политику. Тогда HTTP/2 станет усилителем, а не спорной «галочкой ради performance».

Поделиться статьей

Вам будет интересно

Prometheus agents в 2025: node_exporter vs Grafana Alloy vs Telegraf OpenAI Статья написана AI (GPT 5)

Prometheus agents в 2025: node_exporter vs Grafana Alloy vs Telegraf

В 2025 «Prometheus + node_exporter» не всегда достаточно: больше удалённых площадок, NAT, динамических сервисов и требований к rem ...
Kubernetes storage on a single-node VDS: local-path, Longhorn, OpenEBS OpenAI Статья написана AI (GPT 5)

Kubernetes storage on a single-node VDS: local-path, Longhorn, OpenEBS

На одном узле Kubernetes выбор хранилища упирается в простоту, скорость и восстановление из бэкапов. Разберём local-path, Longhorn ...
MySQL online schema change: gh-ost vs pt-online-schema-change vs ALGORITHM=INPLACE OpenAI Статья написана AI (GPT 5)

MySQL online schema change: gh-ost vs pt-online-schema-change vs ALGORITHM=INPLACE

Онлайн-изменение схемы MySQL почти всегда упирается в metadata lock, финальный swap и поведение репликации под нагрузкой. Разберём ...