Learning Platform
Глоссарий Troubleshooting
Урок 11.04 · 22 мин
Средний
HTTP/3QUICUDPConnection migration0-RTT

HTTP/3 и QUIC — мультиплексирование без TCP HoL blocking

В предыдущем уроке мы обсудили, что HTTP/2 устранил HoL blocking на уровне HTTP, но оставил его на уровне TCP — если один пакет потерян, все streams в этом TCP-соединении ждут retransmit. На стабильных сетях это незаметно. На мобильных и WiFi с потерями — ощутимо. HTTP/3 решает эту проблему радикально: уходит с TCP на UDP.

Звучит парадоксально: UDP — ненадёжный протокол, без гарантий доставки, без подтверждений. Как поверх него построить ровно тот же HTTP, который требует надёжной доставки? Ответ — QUIC. QUIC — это новый транспортный протокол, который повторяет в user-space всё, что делает TCP (надёжность, ordering, congestion control), но проектируется с учётом современных реалий: мобильные сети, мультиплексирование, TLS как первоклассная фича.

В этом уроке разберём, как устроен QUIC, почему его handshake быстрее TCP+TLS, что такое connection migration и почему это меняет правила игры для мобильных приложений.


Откуда взялся QUIC

Google в 2012 году столкнулся с проблемой: их сервисы (Search, YouTube, Maps) на мобильных пользователях работают плохо. Не из-за CPU или backend’а — из-за сети. Высокая latency, частые потери пакетов, переключения между WiFi/LTE. TCP, разработанный в 1970-х, плохо приспособлен к этому миру.

Google запустил эксперимент: gQUIC — свой proprietary протокол поверх UDP. Через несколько лет, поняв, что работает, передал спецификацию в IETF. В 2021 году IETF опубликовал RFC 9000 — стандартизированный QUIC. На его основе сделали HTTP/3 (RFC 9114).

К 2026 году ситуация такая: Google, Cloudflare, Facebook, YouTube, Akamai — все поддерживают HTTP/3. Браузеры (Chrome, Firefox, Edge, Safari) автоматически переключаются на HTTP/3, если сервер его поддерживает. На стороне сервера это всё ещё немного экзотика: nginx поддерживает HTTP/3 экспериментально, Caddy — из коробки, специализированные серверы (Cloudflare’s quiche) — проще всего.


Стек: HTTP/3 -> QUIC -> UDP

Чтобы понять, почему HTTP/3 такой как есть, надо помнить весь стек:

Стек HTTP/3 vs HTTP/2
HTTP/3Семантика та же что HTTP/2: методы, заголовки, статус-коды. Маппинг на QUIC streams вместо HTTP/2 streams. Header compression -- QPACK, модификация HPACK
HTTP/2Binary frames over TCP. HPACK headers compression. Stream multiplexing на уровне HTTP
QUICТранспортный протокол. Streams, reliability, congestion control, встроенный TLS 1.3, connection migration -- всё в одном слое
TCP + TLSHTTP/2 -- TCP внизу, TLS поверх. Два отдельных слоя, каждый со своим handshake'ом
UDPТолько базовая доставка пакетов между host:port. QUIC сам делает reliability, ordering, всё нужное
-
IPСетевой уровень -- маршрутизация. Тот же для всех
IP

Ключевая мысль: QUIC — это полная замена TCP+TLS, реализованная в user-space. Это означает:

  1. Обновления QUIC не требуют изменений ядра ОС — библиотеку обновили, и всё.
  2. TLS встроен — невозможно сделать unencrypted QUIC (в отличие от plain TCP).
  3. Метаданные QUIC шифрованы — middlebox’ы не могут вмешиваться (это и плюс, и минус для firewall’ов).

Решение HoL blocking: streams на уровне транспорта

Главная мотивация: в HTTP/2 мультиплексирование streams делается на уровне HTTP, поверх TCP. TCP не знает про streams — для него это один поток байт. Если пакет потерян, TCP не может отдать «соседние» байты приложению, потому что они могут быть из другого stream, но TCP их не различает.

QUIC переносит концепцию streams в сам транспорт. Каждый пакет QUIC может содержать данные нескольких streams. Если пакет потерян — QUIC может продолжить доставлять данные других streams, только не доставит данные потерянного stream до retransmit.

HoL blocking: TCP vs QUIC
TCP packet AСодержит данные stream 1 и stream 3. Пришёл нормально
TCP packet B lostСодержал данные stream 1. Потерялся. TCP не знает, что 'это была только stream 1' -- он видит gap
TCP packet CСодержит данные stream 3. Пришёл. Но TCP не отдаст его, пока B не восстановят -- TCP гарантирует order
QUIC packet AАналогично -- stream 1+3 в одном пакете. OK
QUIC packet B lostСодержал только stream 1. QUIC ВИДИТ, к каким streams относятся данные
QUIC packet CStream 3 -- независим от потерянного. QUIC отдаёт приложению, не дожидаясь stream 1

Это не значит, что потеря пакета не влияет вообще. Stream 1 ВСЁ РАВНО будет ждать retransmit потерянного фрагмента. Но другие streams (CSS, картинки, JSON-ответы другого API-запроса) продолжают идти. На странице с 50 ресурсами это сильно меняет visible performance.


0-RTT: handshake почти за ноль времени

В TCP+TLS 1.2 классически handshake занимал 2 RTT (TCP 3-way + TLS обмен ключами). TLS 1.3 уменьшил до 1 RTT (TCP + TLS overlapping). QUIC встроил TLS в свой handshake — получается 1 RTT для нового соединения и 0 RTT для повторного.

Handshake: TCP+TLS 1.3 vs QUIC vs QUIC 0-RTT
TCP SYNШаг 1: клиент шлёт SYN. Шаг 2: сервер SYN-ACK. Шаг 3: клиент ACK. 1 RTT потрачен
TLS 1.3 ClientHelloШаг 4: TLS ClientHello. Шаг 5: ServerHello + Certificate + ключи. Шаг 6: client Finished. Ещё 1 RTT (или меньше с TLS 1.3 spec)
Total: 2 RTTТолько потом можно отправлять HTTP-запрос. На 100ms RTT -- 200ms задержки перед первым байтом данных
QUIC initialОдин пакет: содержит и crypto параметры, и начальные TLS-данные. Сервер отвечает одним пакетом -- 1 RTT и handshake готов
QUIC 0-RTTПри повторном соединении с тем же сервером клиент использует кэшированный TLS ticket. Может в первом же пакете послать application data (HTTP request)

0-RTT звучит магически, но имеет нюансы:

  1. Replay attacks. 0-RTT данные не имеют защиты от повтора — атакующий может перезаписать их позже и сервер выполнит снова. Поэтому 0-RTT можно использовать только для безопасных, идемпотентных запросов — GET / HEAD. POST через 0-RTT — опасно.
  2. Forward secrecy не полная. Если у атакующего есть session ticket — он может расшифровать 0-RTT данные. Поэтому tickets должны ротироваться часто.

В реальности 0-RTT даёт огромный выигрыш для повторных запросов на тот же сервер (открыли страничку, через минуту вернулись — мгновенный handshake).


Connection migration

Сценарий: вы смотрите видео на YouTube через WiFi. Выходите из дома, телефон переключается на LTE. Ваш IP-адрес меняется. С TCP — катастрофа: соединение разорвано, нужно установить новое (3-way handshake, TLS, заново). Видео паузится, буферизация.

QUIC решает это через connection migration. Соединение идентифицируется не парой (src_ip:port, dst_ip:port), а специальным Connection ID — 8-байтное случайное число, встроенное в каждый QUIC-пакет.

QUIC connection migration
Client WiFiКлиент с IP 192.168.1.42. Connection ID: 0xABCD1234. Соединение идёт через WiFi-роутер
ServerСервер сохраняет state по Connection ID, не по IP. Знает: connection ABCD = user X, session keys = ...
Switch to LTEТелефон переключился на LTE. Новый IP 100.10.20.30. Но клиент шлёт новый пакет с тем же Connection ID: 0xABCD1234
Server reroutesСервер видит пакет с known Connection ID но новый source IP. Валидирует через path challenge -- сервер шлёт случайный nonce, клиент отвечает -- proof, что это тот же клиент
Streams продолжаютсяВсе streams, которые шли -- продолжают. Видеопоток не паузится, загрузка не прерывается. Незаметно для пользователя

Это фундаментально лучший UX для мобильных приложений. Сейчас приложения вроде Snapchat, TikTok используют это для бесшовного перехода между сетями.


QPACK: header compression без HoL blocking

Помните HPACK в HTTP/2? Там dynamic table обновляется последовательно: каждый header может ссылаться на индексы, которые были раньше. Это работает в TCP (порядок гарантирован), но в QUIC streams могут приходить в любом порядке — HPACK на этом сломался бы.

QPACK — модификация HPACK для work без strict ordering. Использует двунаправленный обмен через два специальных streams (encoder и decoder streams). Чуть сложнее по логике, но работает корректно с QUIC.

В практическом плане для разработчика разницы между HPACK и QPACK нет — библиотека всё делает сама. Знать, что это разные алгоритмы, полезно для отладки и для понимания archive структуры.


Alt-Svc: как сервер сообщает «у меня есть HTTP/3»

Браузер не знает заранее, поддерживает ли сервер HTTP/3. Первое подключение идёт по HTTP/2 (через TLS+TCP). В ответе сервер шлёт заголовок Alt-Svc:

HTTP/1.1 200 OK
Alt-Svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400
Content-Type: text/html

Это значит: «я также доступен по HTTP/3 на порту 443; можешь использовать его следующие 86400 секунд». Браузер на следующем запросе попробует HTTP/3. Если соединение не установится за разумное время — упадёт обратно на HTTP/2.

Alt-Svc — стандартный механизм discovery. Поэтому в production вы видите такой паттерн: первый запрос всегда по HTTP/2, последующие — по HTTP/3.


Минусы и нюансы HTTP/3

Не всё так розово.

  1. UDP заблокирован в некоторых сетях. Корпоративные firewall’ы традиционно блокируют UDP-трафик на всё, кроме DNS (53) и нескольких других портов. QUIC на 443 может не пройти. Клиенты падают на HTTP/2 — но это лишний round-trip на проверку.

  2. Middleboxes ничего не видят. Метаданные QUIC зашифрованы. Network admins не могут сделать deep packet inspection, traffic shaping, content filtering. Это плюс для privacy, минус для контроля. Корпоративные политики могут запрещать QUIC по этой причине.

  3. Сложнее в debugging. Нет tcpdump | grep HTTP — всё в TLS внутри UDP. Нужен Wireshark + SSLKEYLOGFILE для расшифровки. Инструменты ловят up.

  4. CPU нагрузка выше. QUIC реализован в user-space, не в ядре. Каждый пакет проходит через TLS-decrypt в user-space, обработка фрагментации тоже. Бенчмарки показывают, что сервер на HTTP/3 потребляет на 20-30% больше CPU при той же нагрузке, чем HTTP/2 (Linux kernel TCP оптимизирован сильнее, чем user-space QUIC). Поэтому большие сайты часто терминируют QUIC на edge (Cloudflare), а внутри инфраструктуры используют HTTP/1.1 или HTTP/2.

  5. Не все библиотеки поддерживают. На Python: requests — нет. httpx — пока нет HTTP/3. aioquic — есть, но low-level. Это меняется, но в 2026 году большинство API-клиентов в скриптах работают на HTTP/1.1 или HTTP/2.

WARNING

Если вы пишете backend на Python и думаете, что HTTP/3 даст вам выигрыш — скорее всего нет. Backend-to-backend в data center с low latency, no packet loss — HTTP/1.1 keep-alive и HTTP/2 идеально. HTTP/3 имеет смысл на user-facing edge, между мобильным клиентом и CDN.


Реальный пример: проверка HTTP/3 на популярном сайте

# 1. Запросить YouTube -- посмотрите Alt-Svc
curl -sI https://www.youtube.com | grep -i alt-svc
# Что-то вроде: alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000

# 2. Заставить curl использовать HTTP/3 (если установлен curl с http3-поддержкой)
# Обычный curl на macOS/Linux не имеет HTTP/3 -- нужен сборка с quiche или ngtcp2
# Проверить: curl --version | grep -o 'HTTP3'

# 3. Если есть curl с HTTP/3:
curl --http3 -v https://www.cloudflare.com 2>&1 | grep -i 'http/3\|http3'

# 4. Альтернатива: онлайн-чекер
# https://http3check.net/
# Введите домен -- сайт скажет, поддерживает ли HTTP/3

# 5. В Chrome DevTools (F12) -> Network -> Protocol column
# Зайдите на cloudflare.com, youtube.com, twitter.com
# Большинство запросов будут h3
# На первом запросе -- h2, на следующих -- h3 (Alt-Svc сработал)

Что в реальной жизни делать с HTTP/3

HTTP/2 multiplexing и переход на HTTP/3 с точки зрения API

Для junior data engineer советы такие:

  1. На user-facing front-end / CDN. Если ваш сайт публичный, на мобильную аудиторию — включите HTTP/3 на CDN (Cloudflare, Fastly, CloudFront). Бесплатное улучшение latency на мобильных и flaky-сетях.

  2. Backend-to-backend (microservices). НЕ надо. HTTP/1.1 + keep-alive или HTTP/2 в data center — идеально. QUIC overhead тут только мешает.

  3. API-клиенты в скриптах. Не парьтесь. requests / httpx идут на HTTP/1.1 или HTTP/2 — этого достаточно.

  4. Мобильное приложение. Если у вас native app и пользователи на мобильных — HTTP/3 серьёзный буст. Используйте библиотеки (Cronet для Android, NSURLSession с HTTP/3 поддержкой на iOS).


Что вы должны вынести

  1. HTTP/3 = HTTP-семантика, но транспорт — QUIC поверх UDP.
  2. QUIC — замена TCP+TLS в user-space: reliability, streams, encryption — всё в одном слое.
  3. Решает TCP HoL blocking — streams независимы на транспорте.
  4. 0-RTT для повторных соединений (только для safe методов).
  5. Connection migration — соединение переживает смену IP.
  6. Альт-сервер discovery через Alt-Svc header.
  7. Минусы: UDP может быть заблокирован, выше CPU нагрузка, инструменты дебага хуже.
  8. Backend-to-backend HTTP/3 обычно не нужен — польза на user-facing edge.

Проверка знанийKnowledge check
Команда планирует security-аудит API. Раньше они использовали Wireshark, чтобы видеть HTTP-трафик и проверять, какие headers и body летят. После миграции на HTTP/3 они говорят: 'трафик стал нечитаемым в Wireshark, мы не можем дебажить'. Это правда или нет, и какие у них варианты?
ОтветAnswer
Они правы лишь частично. QUIC ЗАШИФРОВЫВАЕТ весь payload (включая HTTP-данные) встроенным TLS 1.3 -- увидеть голый текст HTTP в Wireshark на сетевом интерфейсе НЕЛЬЗЯ. Это сделано намеренно: предотвращает middlebox interference и улучшает privacy. Из tcpdump видны только UDP-пакеты с зашифрованным содержимым, connection ID и публичные QUIC headers. Однако дебаг возможен через несколько подходов: (1) SSLKEYLOGFILE. Chrome/Firefox/curl можно настроить экспортировать TLS-ключи в файл (export SSLKEYLOGFILE=/tmp/keys.log). Wireshark при загрузке pcap и keys log сможет расшифровать QUIC. Это стандартный способ debug в дев-окружении. Для производства не подходит -- ключи -- секрет. (2) Логи на сервере. Включить детальные логи в API (request body sample, headers). Особенно через middleware/interceptor -- сервер видит plain HTTP, может писать в журналы. (3) Дебажить НЕ на сетевом уровне, а на API-уровне -- через клиентские DevTools (Chrome F12) или приложение-прокси (Charles Proxy, mitmproxy с HTTP/3 поддержкой). Прокси работает как man-in-the-middle, расшифровывает HTTPS через свой CA-сертификат, показывает все запросы. Для production debug у Cloudflare/AWS/GCP есть Trace функции, которые логируют HTTP-семантику. (4) Если security audit ТРЕБУЕТ network capture -- можно временно переключить тестируемый endpoint на HTTP/2 для аудита, провести его, вернуть на HTTP/3. Главное: 'нельзя дебажить' -- ложь. Можно, но через другие механизмы, не через простой tcpdump.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 6. Зачем QUIC сделан поверх UDP, а не как 'улучшенный TCP'?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 6