Хоть HTTP/3 все еще находится на стадии подготовки к стандартизации, такие команды как Shopify и Medium, уже внедрили его в продакшн.

Это скриншот с запросами домашней страницы Medium. Большинство из них проходят через протокол HTTP/3 — они помечены как h3–29.

h3 означает HTTP/3, а 29 — номер предварительной версии протокола.

Хоть самым актуальным драфтом является 34-я версия, все известные мне команды выбирают версию 29-ю, поскольку именно обновление было очень объемным. Отличия в более поздних версиях не такие большие.

Так зачем же нам нужен HTTP/3? Одной из важнейших причин является решение проблемы блокировки начала очереди (head‑of‑line blocking).

Блокировка начала очереди в HTTP/2

HTTP/2 решает проблему блокировки начала очереди на уровне HTTP с помощью фреймов (frames) и потоков (streams). Однако проблема остается на уровне TCP.

Получив фреймы со своего верхнего уровня, TCP разбивает их на сегменты.

Если все пойдет хорошо, все сегменты будут доставлены на другой конец.

Однако интернет может быть нестабильным. Некоторые сегменты все‑таки могут быть потеряны в процессе.

TCP имеет функцию, гарантирующую доставку. Он помещает полученные сегменты в буфер и ожидает повторной передачи потерянных сегментов, что и приводит к блокировке начала очереди.

Для решения этой проблемы нужно чем‑нибудь заменить TCP — QUIC и UDP.

Обновленный стек протоколов

Мы видим значительное изменение стека протоколов: TCP был заменен на UDP.

В отличие от TCP, UDP не гарантирует доставку и не создает каких‑либо зависимостей между сегментами. Это означает, что никаких блокировок начала очереди не может быть в принципе.

Кроме того, поскольку UDP является сетевым протоколом передачи без установления соединения, никакого рукопожатия не требуется. По этому он работает быстрее, чем TCP.

В дополнение к UDP был введен новый протокол QUIC. Он наследует сильные стороны TCP, среди которых управление соединениями и потоками данных. Кроме того, QUIC реализует функции, гарантирующие доставку данных, которых недостает UDP.

Другое важное изменение заключается в том, что TLS со всеми своими функциями обеспечения безопасности теперь интегрирован прямо внутри QUIC. Поскольку TLS 1.3 уже готов к работе в продакшене, QUIC внедряет именно эту версию.

И последнее, но не менее важное: QPACK заменяет собой HPACK, что еще больше повышает производительность алгоритма сжатия заголовков. Количество его записей в статической таблице увеличено с 61 до 98, и теперь он имеет нулевой индекс.

Пакеты QUIC, фреймы и потоки

QUICK состоит из пакетов (packet). Пакет в свою очередь состоит из нескольких фреймов (frame).

Ниже приведена структура пакета QUIC:

В заголовке пакета QUIC используются идентификаторы соединения (connection ID или CID), которые отмечают его место назначения (destination) и источник (source).

Браузер и сервер могут выбирать свои идентификаторы. С их помощью мы отделяем соединение от IP и порта, обеспечивая плавную миграцию соединения.

Давайте рассмотрим следующий сценарий, который может происходить с вами несколько раз за день.

Когда вы выходите из дома, ваш мобильный телефон переключается с WiFi на 4G (или даже 5G). Поскольку IP изменяется, TCP переподключается. На мгновение, прежде чем вы снова будете подключены к интернету, вы потеряете соединение.

В QUIC идентификаторы соединений не меняются, поэтому концептуально все соединение остается прежним. Несмотря на изменение IP‑адреса, соединение используется повторно — не нужно никакого переподключения.

А теперь давайте взглянем на пример пакета QUIC:

QUIC IETF
    QUIC Connection information
    [Packet Length: 1350]
    1... .... = Header Form: Long Header (1)
    .1.. .... = Fixed Bit: True
    ..00 .... = Packet Type: Initial (0)
    .... 00.. = Reserved: 0
    .... ..00 = Packet Number Length: 1 bytes (0)
    Version: draft-29 (0xff00001d)
    Destination Connection ID Length: 8
    Destination Connection ID: 45fb5955dfaa8914
    Source Connection ID Length: 0
    Token Length: 0
    Length: 1332
    Packet Number: 1
    Payload: 5a99e5b29413627619ca3b5add4cf8b6ce348355b1c1a2be9874c7961e7996a24aeec860…
    TLSv1.3 Record Layer: Handshake Protocol: Client Hello
    PADDING Length: 997

По публичным флагам 1100 0000, мы можем сказать, что это Long Header, а его тип — Initial. Ниже указана версия QUIC: draft-29, за которой следует идентификатор соединения места назначения и его длина.

Далее мы рассмотрим структуру фрейма QUIC.

Подобно HTTP/2, в QUIC могут быть различные типы фреймов.

Например, фрейм STREAM предназначен для переноса потоков, фрейм ACK предназначен для управления.

Поля в заголовке используют кодирование переменной длины до 8 байтов.

Идентификатор STREAM может достигать 2⁶² с двумя битами, зарезервированными в качестве маркеров.

  • Младший разряд отмечает отправителя: 0 означает клиент, а 1 означает сервер.

  • Второй младший разряд отмечает направление потока: 0 означает двусторонний поток, а 1 — односторонний поток.

Ниже приведен пример фрейма:

TLSv1.3 Record Layer: Handshake Protocol: Client Hello
    Frame Type: CRYPTO (0x0000000000000006)
    Offset: 0
    Length: 314
    Crypto Data
    Handshake Protocol: Client Hello

Тип этого фрейма – CRYPTO, это тип предназначенный для рукопожатия, а полезная нагрузка — криптографические данные.

Вот еще один пример ServerHello:

TLSv1.3 Record Layer: Handshake Protocol: Server Hello

TLSv1.3 Record Layer: Handshake Protocol: Server Hello
  Frame Type: CRYPTO (0x0000000000000006)
  Offset: 0
  Length: 90
  Crypto Data
  Handshake Protocol: Server Hello
    Handshake Type: Server Hello (2)
    Length: 86
    Version: TLS 1.2 (0x0303)
    Random: 0f58bdbd934450c7aa98242121447bef2fe0733aa5fc3beffab6513c7177f9a4
    Session ID Length: 0
    Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301)
    Compression Method: null (0)
    Extensions Length: 46
    Extension: key_share (len=36)
    Extension: supported_versions (len=2)

 За исключением новых полей из фрейма QUIC, все это мы видели в рукопожатии TLS 1.3.

Фреймы протокола HTTP/3

QUIC может многое. Он облегчает рабочую нагрузку HTTP/3.

Например, в отличие от HTTP/2, HTTP/3 использует потоки QUIC вместо того, чтобы определять и контролировать потоки самому.

Большинство типов фреймов, управляемых HTTP/2, перемещены в QUIC, как, например, фреймы RST_STREAM и WINDOW_UPDATE.

Благодаря этому структура фрейма HTTP/3 упрощается до двух полей — типа фрейма (Frame Type) и длины (Length).

Стоит упомянуть еще одну вещь. HTTP/3 не имеет назначенного порта, как 443 для HTTPS.

Браузер сначала подключается к серверу по HTTP/2, чтобы обнаружить службу. Сервер отвечает заголовком Alt-Svc, куда входит порт для HTTP/3, например: Alt-Svc: h3-29=":443". Уже с ним браузер использует QUIC для асинхронного подключения к порту. После создания соединения для дальнейшей связи будет использоваться  HTTP/3.

Ссылки


Когда нужны микросервисы, а когда — монолиты? Поговорим об этом завтра вечером на бесплатном вебинаре в OTUS. Преподаватель расскажет про способы выбора между монолитной или микросервисной архитектурой; участники рассмотрят подходы, а также какие бенефиты можно получить от каждой из этих архитектур, а с чем придется мириться. Открытый урок пройдет в рамках онлайн-курса "Highload Architect".

Комментарии (4)


  1. Drammm
    00.00.0000 00:00

    Лично у меня при тестировании http3 quic на nginx не работали post запросы, а так да - тестирование на живом сайте показывало небольшой прирост скорости загрузки по сравнению с http2. Но почему не работал пост не понял. Нашел только одно сообщение на английском что это не баг а фича…


    1. Demacr
      00.00.0000 00:00

      Что-то припоминаю что для изменяющих запросов (в т.ч. POST) запрещено использовать 0-rtt, т.к. появляется возможность replay атак. Может быть нужно было где-то донастроить сервер.


      1. Drammm
        00.00.0000 00:00

        Вот и не нашел где... Все сеть облазил.


  1. VEG
    00.00.0000 00:00
    +6

    Статья несколько устарела. Финальные версии стандартов QUIC и HTTP/3 уже готовы. Для того, чтобы браузер сразу подключался по HTTP/3, можно использовать новую DNS-запись HTTPS, которая заодно сразу направляет пользователя на HTTPS-версию сайта. То есть, браузеру уже не нужно предварительно отправлять обычный HTTP-запрос через TCP, чтобы получить заголовок Alt-Svc.