Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → HTTP/2 и HTTP/3 (QUIC): что нужно знать разработчику

HTTP/2 и HTTP/3: мультиплексирование, QUIC и практика включения

Разбор протоколов: чем HTTP/2 чинит head-of-line блокировку HTTP/1.1, что даёт QUIC поверх UDP, настройка в nginx и когда HTTP/3 реально ускоряет сайт.

Прямой ответ

Эволюция протоколов решает конкретные боли: HTTP/1.1 — один запрос на соединение за раз (конвейеризация мертва на практике — браузеры открывают 6 параллельных соединений на домен — «спрайты/доменные шардинги» были костылём эпохи); HTTP/2 (RFC 9113) — мультиплексирование: много запросов-ответов одним TCP-соединением параллельно (потоки с приоритетами — head-of-line на уровне HTTP устранён, шардинг доменов стал вреден — всё на один origin), бинарные фреймы, HPACK-сжатие заголовков (повторные запросы почти без заголовочного трафика), server push (спецификация есть — практика мертва: браузеры отказались (Chrome удалил поддержку) — не строить на нём; замена — 103 Early Hints/preload-ссылки); HTTP/3 (RFC 9114 поверх QUIC/RFC 9000) — транспорт на UDP: устраняет TCP-уровня head-of-line (потеря пакета в TCP тормозит все потоки соединения — в QUIC потоки независимы — потеря влияет на один), 0-RTT/1-RTT рукопожатие (TLS встроен в транспорт — первое соединение быстрее — TLS-механика + перенос соединения при смене сети (мобильные: Wi-Fi→LTE без реконнекта — connection ID переживает смену IP — мобильный UX-выигрыш главный). Практика включения для разработчика: HTTP/2 — практически бесплатен (nginx: listen 443 ssl http2; — TLS обязателен де-факто — браузеры h2 без TLS не пользуют; выигрыш максимален на многих мелких ассетах — SPA-бандлы/иконки/шрифты — сборка — десятки файлов одним соединением); HTTP/3 — nginx 1.25+ (listen 443 quic; + add_header Alt-Svc 'h3=":443"; ma=86400'; — браузеры узнают о поддержке через Alt-Svc и пробуют QUIC следующим заходом; UDP 443 открыт в файрволах — частая причина «не работает» — корпоративные сети дропают UDP — fallback на h2/h1 встроен в браузеры автоматически — риск нулевой, выигрыш — мобильным/слабым сетям). Реальность эффекта: «включили h3 — сайт ×2 быстрее» — миф (на быстром проводном интернете разница проценты; выигрыш — высокие RTT/потери/мобильные — аудитория с плохими сетями ускоряется заметно — web vitals полевых пользователей (RUM) покажут, есть ли у вас такая аудитория).

HTTP/2: механика и что менять в коде

Внутренности: соединение → потоки (stream — пара запрос/ответ — идентификатор/приоритет) → фреймы (HEADERS/DATA — бинарные единицы); HPACK — заголовки со словарём+Хаффманом (типичный заголовочный блок 500–1000 байт в 1.1 → десятки байт — на API с частыми запросами — ощутимая экономия — REST-клиенты: httpx с HTTP/2 переиспользует соединение под параллельные запросы — пул соединений меньше); приоритеты/flow control — на поток (медленный клиент не блокирует другие — против 1.1, где один медленный ответ держит соединение). Что меняется в практике разработки: доменный шардинг — убрать (несколько доменов под ассеты были оптимизацией под 6-соединений — в h2 вредны: каждое соединение — своё рукопожатие/медленный старт — один origin лучше — легаси-«cdn1./cdn2./cdn3.» — консолидировать); спрайты — не нужны (иконки отдельными файлами ок — кеш гранулярнее — изображения); конкатенация бандлов — переосмыслить (мега-бандл «чтобы один запрос» — в h2 много мелких не дороги; мелкая гранулярность кешируется лучше — правка модуля инвалидирует килобайты, не мегабайты — баланс по факту — сборка-практика); server push — не использовать (deprecated практикой — 103 Early Hints — preload-заголовки до HTML — CDN/браузеры поддерживают растуще); gRPC-внутри (gRPC построен на h2 — gRPC-статья — потоки/мультиплексирование те же); WebSocket поверх h2 (RFC 8441 — поддержка частичная — практика — обычный WS — WebSocket); проверка работы — DevTools Protocol-колонка (h2 в Network-таблице), curl --http2 -I, nghttp — детальная трассировка потоков (отладка мультиплексирования).

HTTP/3 и QUIC: транспорт и включение

QUIC-основы: UDP как носитель (своя надёжность/порядок/шифрование внутри — TLS 1.3 встроен — каждый пакет шифрован, включая большую часть метаданных рукопожатия — приватность+быстрота); рукопожатия: 1-RTT первое, 0-RTT повторное (данные в первом пакете — ранние данные; 0-RTT — replay-риск (перехваченные ранние данные могут быть повторены — идемпотентность 0-RTT-запросов — GET ок, POST — серверная защита/не принимать — тонкость, о которой забывают); connection migration (ID соединения вместо IP-пары — смена сети не рвёт сессию — видеозвонок/загрузка в метро переживают переключения — мобильный главный кейс); независимость потоков (потеря пакета — только его поток ждёт ретрансмита — остальные живут — на сетях с потерями 1–2% (мобильные/спутник/дальние RTT) — разница с TCP драматична; на чистом проводном — почти незаметна). Включение (nginx 1.25+): listen 443 quic reuseport; + listen 443 ssl http2; (параллельно — h3 для умеющих, h2/h1 остальным — одновременная работа обязательна — UDP-блокировки в сетях реальны), add_header Alt-Svc 'h3=":443"; ma=86400'; (анонс — браузер после успешного h2-захода пробует h3 — «первый визит h2, последующие h3» — нормальное поведение — тестировать «вторым заходом»), файрвол — UDP 443 открыть (диагностика: tcpdump udp port 443 — доходят ли; сервер за облачным LB — поддержка h3 у провайдера — Cloudflare/ALB включают своей настройкой); MTU/фрагментация UDP (промежуточное оборудование режет большие UDP — QUIC адаптируется PMTUD — редкие «h3 висит» — диагностика PING-фреймами/логи nginx debug); проверка — DevTools Protocol «h3», curl --http3 (сборка с поддержкой), cloudflare-quic.com-класс тест-страниц; аналитика доли h3 — RUM/логи провайдера (метрики — доля h3-сессий растёт после включения — 30–60% трафика за недели — браузеры переходят постепенно).

Практический сценарий: каталог на 400 ассетов — от 1.1 к h2/h3

Исходник: интернет-магазин за nginx (TLS есть, HTTP/1.1): страница товара — 87 запросов (бандлы, 40 иконок-отдельных файлов после давнего «спрайты зло»-рефакторинга, шрифты, картинки — картинки уже в AVIF); LCP на 3G-профиле — 5.9 с; часть ассетов на cdn2.домене (шардинг-наследие 2019 года). Шаг 1 — HTTP/2: listen 443 ssl http2; + консолидация cdn2 → основной origin (шардинг убран — DNS-предредирект оставлен на квартал), preload-ссылки на критичные бандлы в HTML (замена «пушу»); результат: 87 запросов — одним соединением (Network-панель: одна колонка h2), 3G-LCP — 3.8 с (−36%), проводной — 1.9→1.6 с; проверка curl --http2 — протокол подтверждён; шаг 2 — HTTP/3 (nginx 1.25 собран из пакетов — пакетная дисциплина в инфраструктурном варианте): quic-listener + Alt-Svc + UDP 443 в файрволе (проверка tcpdump — пакеты доходят); полевой замер через месяц (RUM-данные аналитики): доля h3 — 41% сессий, LCP p75 мобильной аудитории (LTE/слабый Wi-Fi) — −22% (3.1→2.4 с), проводная аудитория — −3% (ожидаемо — выигрыш там, где сети плохие); поддержка: два инцидента «h3 не работает» — оба корпоративные сети с UDP-дропом (браузер сам откатился на h2 — пользователи не заметили — механизм fallback отработал как спроектировано); мониторинг: доля протоколов в дашборде (Grafana — nginx-логи с $server_protocol) — тренд h3-миграции виден; вывод команды: h2 — обязательная база (бесплатно и везде), h3 — дешёвое включение с выигрышем мобильным — «включить и забыть» при работающем fallback. Открытый хвост: 0-RTT не включали (POST-трафик через API — replay-защита не реализована — осознанное решение — ADR — экономия 100 мс не стоит риска без нужды).

FAQ

Нужен ли HTTP/2 для внутреннего API (сервис-сервис)? Зависит от профиля: много мелких параллельных запросов между сервисами — h2 даёт (мультиплексирование/HPACK — httpx-клиент с http2=True — одно соединение вместо пула — меньше портов/TIME_WAIT — сетевая диагностика показывает разницу); gRPC — уже h2 внутри; редкие тяжёлые запросы — выигрыш мал (h1.1 достаточен); «h2 обязателен везде» — нет: профиль нагрузки решает, но для клиент-браузер трафика — h2 де-факто стандарт (браузеры на h1.1-сайтах теряют производительность молча).

Почему HTTP/3 на UDP, если UDP ненадёжен? QUIC реализует надёжность/порядок/контроль перегрузки поверх UDP в пользовательском пространстве (своя реализация того, что TCP делает в ядре — со всеми накладными, но со свободой эволюции: независимые потоки, встроенный TLS, миграция — в TCP это не вставляется без слома совместимости — десятилетия ossified-протокола); UDP выбран как «тонкая прослойка, которую пропустят» (ядро-TCP менять нельзя, UDP — есть везде); надёжность для приложения та же (QUIC гарантирует доставку потока — потерь на уровне приложения нет); цена — CPU на обработку в userspace (серверная нагрузка выше TCP на 10–25% — железо дешевеет, выгоды мобильным реальны — баланс принят индустрией).

Ломает ли HTTP/3 существующий код приложения? Нет — прикладной слой не видит транспорта (HTTP-семантика та же — методы/заголовки/тело; nginx/прокси терминируют QUIC — приложение получает обычный запрос); нюансы инфраструктурные: UDP-файрволы, логи (протокол в лог-формат — $server_protocol), MTU-диагностика, клиентские библиотеки (httpx/aioquic — h3 клиентская поддержка экспериментальна — серверная зрелая); «приложение должно поддерживать h3» — миф (прокси-слой решает — приложение не меняется — та же причина, по которой переход 1.1→2 был незаметен коду).

Что с HTTP/2 server push — почему все отказались? Push позволял серверу прислать ресурсы до запроса (идея: HTML+CSS сразу); практика сломалась: пуш не знает кеш браузера (пушит уже имеющееся — трафик впустую), гонки с парсером (браузер сам находит preload раньше), сложность приоритизации; Chrome удалил поддержку (2022), остальные следовали; замена — 103 Early Hints (сервер шлёт preload-заголовки до готового HTML — браузер начинает загрузку раньше — кеш уважается — CDN-провайдеры поддерживают) и обычный <link rel=preload> — «push мёртв, ранние подсказки живы» — строить на preload, не на push.

Источники: RFC 9113 (HTTP/2), RFC 9000 (QUIC), документация nginx http_v3 — ссылки в шапке.