Сети и протоколы
HTTP/3 в продакшне: внутренности QUIC, fallback и наблюдаемость
Ваш edge-сервис включает HTTP/3. Однажды утром дашборд ALPN показывает: доля h3 упала с 40% до 5%. Ошибок в логах приложения нет. Пользователи не звонят. Что сломалось? Это инцидент HTTP/3 в продакшне — и путь диагностики совсем не похож на TCP-outage.
TCP HOL-блокировка: точный механизм
Антагонист HTTP/2 — контракт доставки TCP. TCP гарантирует доставку в порядке байтового потока. Когда сегмент с байтами 50 000–50 099 потерян, TCP буферизует все последующие байты до повторной передачи потерянного сегмента. Буфер приёма TCP в ядре заполняется; ни один байт не движется к приложению. На уровне HTTP/2 поток #1 может использовать байты 50 000–50 099, поток #2 — байты 50 100–50 199: оба встают на ожидание повторной передачи.
Метрика: при 1% потере пакетов и RTT 100 мс ожидается примерно одно событие потери на 100 пакетов, с задержкой ~100 мс на событие. При 50 параллельных потоках эта задержка затрагивает все 50. На каналах с высокими потерями (мобильная сеть 0,5–2%, спутник 2–5%) HTTP/2 ощутимо проигрывает HTTP/1.1 с 6 параллельными TCP-соединениями — потому что параллельные соединения имеют независимые домены восстановления потерь.
Независимость потоков QUIC: точный механизм
QUIC нумерует пакеты, а не байтовые смещения единого потока. Каждый QUIC-пакет подтверждается отдельно. Каждый поток отслеживает, какие пакеты несли его фреймы и какие ещё в полёте.
Когда пакет N потерян:
- QUIC повторно передаёт конкретные фреймы потоков A и C, которые были в пакете N.
- Потоки B, D и E — чьи фреймы были в других пакетах — продолжают отправлять и получать.
- Прикладной уровень для потока B не видит прерывания.
Цена: заголовки QUIC-фреймов добавляют накладные расходы (stream ID, смещение, длина на фрейм — ~8–10 байт каждый, против TCP-сегмента без накладных расходов на поток). Состояние на соединение тяжелее. Но на каналах с потерями выигрыш решающий.
HPACK vs QPACK: зависимость от порядка
HPACK (RFC 7541) поддерживает динамическую таблицу, индексированную по последовательности вставок. Запись под индексом 62 — это 62-я пара (имя, значение), вставленная с начала соединения. HEADERS-фрейм, ссылающийся на индекс 62, должен быть обработан после фрейма, который вставил индекс 62.
На TCP: фреймы приходят в порядке — HEADERS-фрейм, добавляющий индекс 62, всегда приходит раньше HEADERS-фреймов, ссылающихся на него. Ограничение порядка невидимо.
На QUIC: потоки доставляют фреймы независимо. HEADERS-фрейм в потоке #3 может прийти раньше HEADERS-фрейма в потоке #1, который добавил бы индекс 62. Если HEADERS потока #3 ссылается на индекс 62, декодирование провалится или заблокируется.
Решение QPACK (RFC 9204):
- Encoder stream — выделенный однонаправленный QUIC-поток несёт вставки в динамическую таблицу. Этот поток доставляет обновления таблицы в порядке.
- Decoder stream — несёт подтверждение о том, какие записи таблицы были обработаны.
- HEADERS-фреймы — ссылаются только на записи, которые энкодер знает как подтверждённые на decoder stream. HEADERS-фрейм в потоке #3 никогда не ссылается на запись, которая может ещё не быть в таблице декодера.
Результат: HEADERS-фреймы одного потока никогда не могут блокироваться HEADERS-фреймами другого потока — независимость потоков QUIC сохраняется на уровне сжатия заголовков.
- Глобальная доля HTTP/3-трафика
- 21.1% (Cloudflare Radar)
- Сайты, рекламирующие HTTP/3
- 38.8% (W3Techs)
- Google, Meta, Cloudflare, Akamai — доля h3
- >50% их трафика
- Типичный процент блокировки UDP/443 корпоративными firewall'ами
- 5–15% корпоративных путей
- Стоимость fallback HTTP/3 → HTTP/2 в RTT
- +1 RTT при первом визите
- Окно риска повтора 0-RTT данных
- Срок действия сессионного тикета
Переговоры о версии: ALPN и цепочка fallback
Для HTTP/1.1 и HTTP/2: ALPN (RFC 7301) — расширение TLS. Во время TLS-хендшейка клиент шлёт список поддерживаемых протоколов (["h2", "http/1.1"]). Сервер выбирает один. Без дополнительных round-trip — переговоры о версии бесплатны внутри хендшейка.
Для HTTP/3: переговоры двухэтапные, потому что QUIC/UDP — другой транспорт:
- Первое соединение использует TCP-based HTTP/1.1 или /2.
- Ответ сервера включает
Alt-Svc: h3=":443"; ma=86400(или HTTPS/SVCB DNS-запись). Браузер сохраняет эту подсказку. - Последующие соединения к этому origin: браузер пробует QUIC/UDP первым, с TLS ALPN, выбирающим
h3. - Если UDP/443 заблокирован (QUIC-хендшейк не прошёл): браузер помечает этот origin как «h3 недоступен» на период cooldown и откатывается к TCP-based HTTP/2.
Fallback тихий — пользователи не видят ошибок, но операторы должны мониторить метрики ALPN-распределения. Пик h3→h2 fallback — сигнал изменения сетевого пути, блокирующего UDP/443.
Коалесценция соединений
Несколько origin’ов, разделяющих один IP edge-сервера и охваченных TLS-сертификатом, могут использовать одно HTTP/2 или HTTP/3 соединение — коалесценция соединений. Пример: cdn.example.com и api.example.com оба резолвятся в один IP, и edge-сертификат покрывает оба имени в SAN (Subject Alternative Names). Chrome и Firefox коалесцируют: одно QUIC-соединение обслуживает запросы к обоим hostname’ам.
Это экономит стоимость хендшейка на страницах, загружающих ресурсы с нескольких origin’ов на одном CDN. Подводный камень: если список SAN сертификата не включает один из коалесцируемых hostname’ов (мискофигурация), браузер открывает отдельное соединение — тихая регрессия задержки. Мониторьте количество соединений на origin; внезапный рост сигнализирует о сбое коалесценции.
Управление перегрузкой в QUIC userspace
Управление перегрузкой TCP (CUBIC, BBR, Reno) работает в ядре операционной системы. QUIC реализует управление перегрузкой в userspace — внутри приложения или библиотеки QUIC.
Следствия:
- Гибкость: операторы могут настраивать или менять алгоритмы на соединение, на приложение или на класс трафика без изменения ядра.
- CPU-стоимость: вычисления управления перегрузкой выполняются в процессе, конкурируя с кодом приложения за CPU. При большом числе соединений это ощутимо.
- Наблюдаемость: каждое QUIC-соединение должно экспортировать свои измерения окна перегрузки, скорости потерь и RTT. TCP в ядре экспортирует их через
/proc/net/tcpиss; QUIC требует хуков телеметрии на соединение.
Формат qlog IETF (JSON-лог событий на соединение) — инструмент глубокой отладки для QUIC. Для продакшна экспортёры Prometheus/OTel агрегируют QUIC-метрики по соединениям.
0-RTT replay: операционный риск
Возобновление 0-RTT (через TLS-сессионные тикеты) позволяет браузеру отправить HTTP-запрос в самом первом QUIC-пакете, до завершения хендшейка. Это экономит один RTT (~50–300 мс на дальних каналах).
Риск: 0-RTT данные могут быть повторены сетевым злоумышленником. Атакующий, перехвативший первый QUIC-пакет, может переслать его, заставив сервер обработать запрос второй раз. Для GET-запросов (идемпотентных, без побочных эффектов) это безвредно. Для POST (создание заказа, отправка платежа) — катастрофа.
Требования для продакшна:
- Сервер должен отслеживать и отклонять повторённые 0-RTT данные (через anti-replay токены — RFC 9001 § 9.2).
- Серверы должны отвечать
425 Too Earlyдля небезопасных методов в 0-RTT. - Хранилище anti-replay токенов: ограниченное; на крупных распределённых развёртываниях нужен общий кэш (Redis) для обнаружения повторов на разных edge-узлах.
Диагностика: доля HTTP/3-трафика сервиса упала с 40% до 5% за ночь.
Дашборд наблюдаемости: обнаружение пика HTTP/3-fallback
# Prometheus-метрики с CDN edge, апрель 2026
## Распределение ALPN-протоколов (скользящее среднее 5 минут)
tls_alpn_protocol{protocol="h3"} 21.1% # Нормальный базовый уровень
tls_alpn_protocol{protocol="h2"} 51.3%
tls_alpn_protocol{protocol="http/1.1"} 27.6%
## Скорость fallback (h3 пробовался, но откатился на h2)
http3_to_http2_fallback_rate 0.8% # Базовый уровень: нормальные потери/блокировка ISP
## В 14:35 UTC 2026-04-15 срабатывает alert: скорость fallback растёт
http3_to_http2_fallback_rate 18.2% # 23x нормы
tls_alpn_protocol{protocol="h3"} 1.3% # Упал с 21.1%
## Геолокационная разбивка показывает: пик сконцентрирован
fallback_rate{region="US-Northeast", ISP="AS7922"} 67.4%
fallback_rate{region="US-Midwest"} 2.1%
fallback_rate{region="Europe"} 1.9%
## Сетевая диагностика с edge-узла
$ mtr -P UDP/443 route-to-AS7922-customer
hop 5: (AS7922 transit edge) UDP packets: 0% loss [OK]
hop 6: (AS7922 DDoS scrubber, новое правило: 2026-04-15 14:00 UTC)
UDP packets: 100% loss [BLOCKED]
hop 7+: unreachable Пик HTTP/3-fallback появился для трафика одного ISP (AS7922, US-Northeast), но нигде больше. MTR показывает, что UDP доходит до хопа 5 без потерь. Где блок и какова вероятная причина?
Вывод curl -v для ошибочно настроенного HTTP/3-сервера
$ curl --http3-only -v https://api.example.com/health
* Trying 203.0.113.42:443...
* QUIC handshake fail: protocol violation: invalid initial packet
* Closing connection
curl: (35) QUIC handshake fail: protocol violation: invalid initial packet
$ curl -v https://api.example.com/health
* Connected to api.example.com (203.0.113.42) port 443
* ALPN: offers h2,http/1.1
* ALPN: server accepted h2
< HTTP/2 200 OK
< alt-svc: h3=":443"; ma=86400
< server: nginx/1.27.0
< x-quic-version: draft-29
< content-type: application/json
{"status":"ok"} HTTP/3 явно падает с 'protocol violation: invalid initial packet', но сервер рекламирует h3 через Alt-Svc. В чём мискофигурация и как исправить?
Какой RFC определяет транспортный протокол QUIC (не сам HTTP/3, не TLS-over-QUIC)?
Вы разворачиваете HTTP/3 для глобального API с 10k req/s из 50+ стран, ожидая, что 5–15% путей блокируют UDP/443. Спроектируйте стратегию rollout HTTP/3.
- Часть корпоративных и операторских сетей тихо блокирует UDP/443.
- Нельзя сломать существующих HTTP/1.1 и HTTP/2 клиентов.
- Мобильные пользователи на сотовой связи — приоритетная цель для изоляции потерь HTTP/3.
- SRE-команда должна обнаруживать инциденты блокировки UDP в течение 5 минут.
- Обслуживать все три версии; ALPN и Alt-Svc управляют выбором.
- Начать с короткого Alt-Svc max-age во время rollout, увеличить после стабилизации.
- Alert на h3-fallback-rate по региону/ASN — это ваш сигнал здоровья сети.
- 0-RTT безопасен только для идемпотентных методов; 425 Too Early для POST.
- Проверить, что SAN edge-сертификата покрывает все коалесцируемые origin'ы.
- 01Объясните, почему QPACK существует отдельно от HPACK.
- 02Инженер говорит, что HTTP/3 всегда лучше HTTP/2 из-за потоков QUIC. Где изъян в рассуждении?
- 03Что такое коалесценция соединений и что её ломает?
Эксплуатация HTTP/3 в продакшне фундаментально зависит от надёжности UDP-пути и операционной наблюдаемости. Независимость потоков QUIC означает, что один потерянный пакет останавливает только потоки, чьи данные он нёс — но это требует пакетного отслеживания потерь QUIC (не байтовой модели TCP) и encoder/decoder control streams QPACK (не упорядоченной динамической таблицы HPACK). Управление перегрузкой QUIC работает в userspace — гибче, но CPU-интенсивнее. Переговоры о версии для HTTP/3 используют Alt-Svc или HTTPS/SVCB DNS и тихо откатываются на HTTP/2 при блокировке UDP/443 — ALPN-метрика распределения — сигнал. Коалесценция соединений экономит стоимость хендшейка для origin’ов, разделяющих один IP и SAN сертификата. 0-RTT экономит round-trip, но требует server-side anti-replay и должен быть ограничен идемпотентными методами.
встречается в5
- MVCC: как Postgres раздаёт согласованные снимкиjunior
- Акт 7 в глубину: шардинг, co-location и семиуровневый каскад трейдоффовmiddle
- Наблюдаемость, антипаттерны и производственный триажsenior
- Raft в реальном мире: partition, медленный диск и клиентская маршрутизацияmiddle
- Raft в production: membership change, Multi-Raft и observabilitysenior