HTTP/2, HTTP/3 (QUIC) и сетевая инфраструктура
HTTP/1.1 прожил больше двадцати лет, и всё это время у него была одна и та же болезнь: по одному TCP-соединению нельзя честно гнать несколько запросов параллельно. Браузеры лечили это костылями (несколько соединений к домену, склейка ассетов), но болезнь оставалась. HTTP/2 и HTTP/3 это две попытки вылечить её по-настоящему, и вторая дошла до того, что выкинула TCP.
Это финальный урок раздела. Сначала разберём, как менялся сам протокол, потом поднимемся на уровень выше кода, к маршрутизации, CDN и VPN, которые переносят все эти пакеты между континентами.
Болезнь HTTP/1.1: head-of-line blocking
У HTTP/1.1 четыре врождённые болячки, и все растут из одного корня: по одному TCP-соединению запросы идут строго по очереди.
- Head-of-line blocking. Конвейер (pipelining) теоретически разрешал слать несколько запросов, не дожидаясь ответов, но ответы обязаны вернуться в том же порядке. Застрял первый, ждут все за ним. Это head-of-line blocking. Из-за него pipelining на практике почти никто не включал, он по умолчанию выключен в браузерах.
- Дорогие соединения. Каждое новое соединение это рукопожатия TCP и TLS, несколько round-trip до первого байта. Чтобы грузить страницу параллельно, браузер открывал по 6 соединений на домен, и каждое платило за старт.
- Заголовки без сжатия.
Cookie,User-Agent,Acceptшлются целиком в каждом запросе. На странице с сотней ассетов это килобайты повторов на каждый запрос. - Нет приоритетов. Сервер не знает, что CSS важнее аналитики, и отдаёт в порядке поступления.
Лечили это костылями на стороне фронтенда: открывали несколько соединений к домену, размазывали ассеты по поддоменам (domain sharding), склеивали скрипты в бандлы, картинки в CSS-спрайты, мелкие ресурсы инлайнили в HTML. Всё это лечение симптомов, а не причины, и в эпоху HTTP/2 такие приёмы из полезных стали вредными.
HTTP/2: мультиплексирование поверх одного TCP
HTTP/2 переписал транспорт под капотом, оставив семантику (методы, статусы, заголовки) прежней. Ключевые идеи:
- Бинарные фреймы вместо текста.
- Мультиплексирование: десятки запросов по одному соединению одновременно, ответы приходят как готовы, без очереди.
- HPACK
сжатие заголовков: повторяющиеся
CookieиUser-Agentне гоняются целиком. - Server push (сервер сам шлёт ресурсы наперёд) появился, не прижился и фактически удалён, на практике его не используют.
Версию протокола на TLS-рукопожатии выбирает ALPN.
Как устроен мультиплексинг изнутри
Магия мультиплексирования это всего лишь нарезка на фреймы. Каждое сообщение HTTP/2 разбивается на кадры фиксированного формата: 9 байт заголовка (длина, тип, флаги, stream id) плюс полезная нагрузка. Типы кадров, которые стоит знать:
- HEADERS заголовки запроса или ответа.
- DATA кусок тела.
- stream это логический поток: HEADERS открывает его, DATA-кадры досылают тело, и у всех кадров одного потока общий нечётный stream id.
SETTINGS,WINDOW_UPDATE(управление потоком, flow control на уровне stream),RST_STREAM(отмена одного потока без разрыва соединения),PRIORITY(подсказка приоритета).
Ключевой трюк: кадры разных stream свободно чередуются на одном проводе. Приёмник смотрит на stream id в заголовке кадра и собирает перемешанный поток обратно в нужные сообщения. Поэтому медленный крупный ответ больше не держит очередь: его DATA-кадры просто едут вперемешку с кадрами быстрого ответа.
Покрути переключатель и пошагай: тот же набор кадров, но в HTTP/1.1 они уходят строго по очереди, а в HTTP/2 чередуются.
Поэтому старые приёмы оптимизации в HTTP/2 стали вредными: domain sharding плодит лишние соединения и мешает мультиплексированию, а большие бандлы рушат кеширование. С HTTP/2 правильнее много мелких ресурсов по одному соединению.
HOL вернулся, но ниже
Но осталась тонкость: мультиплексирование живёт поверх TCP, а TCP это единый упорядоченный поток. Потеряли один пакет, и TCP тормозит доставку всем логическим потокам сразу, пока не переотправит. Head-of-line blocking никуда не делся, он просто спустился с прикладного уровня на транспортный. Виджет выше показывает идеальный случай без потерь, но стоит одному TCP-сегменту потеряться, и все stream замирают вместе.
дальше после входа
Урок целиком открыт всем, кто вошёл. Войди по своему email, чтобы читать дальше.
Вход пока по приглашению. Если хочешь учиться, напиши Vassiliy.