С 2017 года было выпущено 34 проекта протокола HTTP3, которые скоро будут выпущены. Chrome, Nginx и другое программное обеспечение продолжают реализовывать последний проект. В этой статье будут представлены спецификации протокола HTTP3, сценарии применения и принципы реализации.
После официального запуска протокола HTTP2 в 2015 году его использует почти половина всех интернет-сайтов:
(Изображение изhttps://w3techs.com/technologies/details/ce-http2) Хотя протокол HTTP2 значительно улучшил производительность HTTP/1.1, однако реализация HTTP2 на основе TCP оставляет три проблемы:
Протокол HTTP3 решает эти проблемы:
Эта статья начнется с концепции протокола HTTP3.,Изучите формат сообщений HTTP3 на примере реализации миграции соединения.,Затем сосредоточьтесь на проблеме блокировки начала строки для анализа реализации мультиплексирования и динамических таблиц QPACK. Хотя официальная спецификация RFC еще не опубликована.,Но последнее изменение проекта содержит лишь незначительные изменения.,Итак, сейчас самое время изучить HTTP3,Это будет самая важная инфраструктура для Интернета следующего поколения.。Эту статью тоже написал я2020Год8луна3ЧислоКитайское сообщество NginxиQCONсовместно организованныйОткрытый урок QCONТекстовое резюме части контента。
Как и протокол HTTP2, HTTP3 не меняет семантику HTTP1. Так что же такое семантика HTTP? На мой взгляд, оно включает в себя следующие 3 пункта:
HTTP3 меняет формат кодирования, сохраняя при этом семантику HTTP1. Это происходит по двум причинам:
Во-первых, это уменьшение длины кодирования. На рисунке ниже в кодировке протокола HTTP1 используется код ASCII с использованием пробелов, двоеточий и \r\n в качестве разделителей. Эффективность кодирования очень низкая:
HTTP2 и HTTP3 используют двоичную, статическую таблицу, динамическую таблицу и алгоритм Хаффмана для кодирования заголовка HTTP, что не только обеспечивает высокую степень сжатия, но также ускоряет кодирование отправителя и декодирование получателя.
Во-вторых, поскольку протокол HTTP1 не поддерживает мультиплексирование, такого высокого уровня параллелизма можно достичь только за счет открытия большего количества TCP-соединений. Однако есть три недостатка достижения высокого уровня параллелизма через TCP:
Таким образом, и HTTP2, и HTTP3 реализуют функции мультиплексирования на уровне приложения:
(Изображение из:https://blog.cloudflare.com/http3-the-past-present-and-future/)
HTTP2протокол реализован на основе упорядоченного потока байтов TCP.,поэтомуМультиплексирование на уровне приложения не может обеспечить неупорядоченный параллелизм, и проблема блокировки начала строки возникает в сценариях потери пакетов.Как показано на динамическом изображении ниже,Зеленый ответ, возвращаемый сервером, состоит из 5 TCP-сообщений.,Желтый ответ состоит из 4 TCP-сообщений.,Когда потерян второй желтый пакет,Даже если клиент получит полные 5 зеленых пакетов,Но уровень TCP не позволит функции чтения процесса приложения прочитать последние 5 сообщений.,Параллелизм стал бумажкой:
Когда сеть занята, вероятность потери пакетов будет очень высока, а мультиплексирование будет сильно ограничено. поэтому, HTTP3 использует UDP в качестве протокола транспортного уровня для повторной реализации неупорядоченных соединений и на этой основе использует упорядоченный QUIC. Поток обеспечивает мультиплексирование , как показано на рисунке ниже:
(Изображение из:https://blog.cloudflare.com/http3-the-past-present-and-future/)
Этот экспериментальный протокол был впервые запущен Google и назван gQUIC. Поэтому концепция QUIC все еще сохраняется в проекте IETF для описания транспортного уровня и уровня представления протокола HTTP3. Спецификация протокола HTTP3 состоит из следующих пяти частей:
Протокол HTTP/0.9, появившийся в 1991 году, больше не используется. Однако протоколы HTTP/1.0, запущенные в 1996 году, HTTP/1.1, запущенные в 1999 году, и протоколы HTTP2, запущенные в 2015 году, до сих пор сосуществуют в Интернете (HTTP/1.0 до сих пор широко используется в корпоративных интрасетях. Например, протокол по умолчанию между Nginx и восходящим потоком — версия 1.0), добавление будущего протокола HTTP3 еще больше усложнит адаптацию протокола. . Далее мы углубимся в детали протокола HTTP3.
Для текущего протокола HTTP1 и HTTP2,Перед передачей запроса необходимо выполнить трехстороннее подтверждение TCP, требующее 1 RTT, и подтверждение TLS, требующее 1 RTT (TLS1.3).,Потому что они принадлежат транспортному уровню, реализованному ядром, и уровню представления, реализованному библиотекой openssl.,Так сложно слиться воедино, как показано на рисунке ниже:
(Изображение из:https://blog.cloudflare.com/http3-the-past-present-and-future/)
В эпоху Интернета вещей,Сеть, к которой получают доступ мобильные устройства, часто меняется,тем самым вызывая устройствоIPИзменение адреса。Для протокола TCP, который находит соединения через четыре кортежа (IP-адрес источника, порт источника, IP-адрес назначения, порт назначения), это означает, что соединение необходимо отключить и повторно подключить, поэтому задержка установления соединения для двух вышеупомянутых RTT и TCP медленная. start Все нужно делать заново.иHTTP3изQUICслой Реализована функция миграции,После разрешения мобильным устройствам менять IP-адреса,Пока контекстная информация (например, идентификатор соединения, ключ TLS и т. д.),Вы можете повторно использовать исходное соединение.
Между заголовком сообщения UDP и сообщением HTTP существует три уровня заголовков, которые определяют соединение и реализуют соединение. Миграция в основном происходит в пакетном режиме. Завершено в заголовке, как показано на рисунке ниже:
Функции, реализуемые этими тремя уровнями заголовка, различны:
Чтобы еще больше повысить эффективность передачи по сети, заголовок пакета можно разделить на два типа:
Среди них формат длинного заголовка пакета показан на рисунке ниже:
При установлении соединения соединение выделяется сервером через поле «Идентификатор исходного соединения». Таким образом, во время последующей передачи обеим сторонам нужно только зафиксировать идентификатор целевого соединения, чтобы обойти четверку UDP (так же, как четверку TCP). реализовать функцию миграции соединений. На следующем рисунке показан формат заголовка короткого заголовка пакета. Здесь нет необходимости передавать поле идентификатора исходного соединения:
Номер пакета на рисунке выше представляет собой уникальный порядковый номер для каждого пакета. На его основе можно добиться точной повторной передачи потерянных пакетов. Если вы просмотрите заголовок пакета при перехвате пакета, вы обнаружите, что номер пакета защищен шифрованием уровня TLS. Это конструкция для предотвращения различных сетевых атак. На следующем рисунке показаны зашифрованные поля в заголовке пакета:
Среди них поле, показанное как E (Шифрование), указывает на то, что оно было зашифровано с помощью TLS. Конечно, заголовок пакета описывает только самую основную информацию о соединении, а уровень потока и HTTP-сообщения над ним также зашифрованы и защищены:
Теперь, когда у нас есть базовое представление о формате протокола HTTP3, давайте рассмотрим форматы кадров QUIC и HTTP3 в пакете через проблему блокировки начала строки.
Фактически, решение проблемы блокировки начала строки состоит в том, чтобы позволить пакетным сообщениям, отправленным в микроскопическом порядке, применяться к одновременным запросам после того, как они прибывают на принимающую сторону в неправильном порядке. Например, на приведенной выше динамической диаграмме, если потерянный желтый пакет не влияет на последующий зеленый пакет, проблема блокировки начала строки естественным образом будет решена:
Заголовок кадра QUIC поверх заголовка пакета определяет упорядоченный поток байтов Stream, и между потоками может быть достигнут настоящий параллелизм. Поток HTTP3 заимствует некоторые концепции из HTTP2, поэтому, прежде чем обсуждать формат заголовка кадра QUIC, давайте сначала посмотрим, как выглядит поток в HTTP2:
(Изображение см.:https://developers.google.com/web/fundamentals/performance/http2)
Каждый поток похож на TCP-соединение в HTTP1. Он гарантирует, что кадр HEADERS (заголовок HTTP хранилища) и кадр DATA (тело HTTP хранилища), которые он несет, доставляются в порядке, и несколько потоков могут передаваться параллельно. В HTTP3 кадр HTTP2 на рисунке выше будет разобран на два слоя. Давайте сначала посмотрим на базовый кадр QUIC.
В пакетном сообщении может храниться несколько кадров QUIC. Разумеется, сумма длин всех кадров не может превышать PMTUD (обнаружение максимального блока передачи), значение которого превышает 1200 байт. Концепция MTU в IP-маршрутизации Сравните и поймите:
Каждый фрейм имеет четкий тип:
Первые 4 байта поля «Тип кадра» описывают разные типы, а также различаются следующие кодировки. В следующей таблице показаны шестнадцатеричные значения «Тип» различных типов кадра:
Value | Name | Value | Name |
---|---|---|---|
0x00 | PADDING | 0x02 – 0x03 | ACK |
0x01 | PING | 0x08 – 0x0f | STREAM |
0x04 | RESET_STREAM | 0x12-0x13 | MAX_STREAMS |
0x05 | STOP_SENDING | 0x16-0x17 | STREAM_BLOCKED |
0x06 | CRYPTO | 0x1c-0x1d | CONNECTION_CLOSE |
0x07 | NEW_TOKEN | 0x11 | MAX_STREAM_DATA |
0x10 | MAX_DATA | 0x14 | DATA_BLOCKED |
0x15 | STREAM_DATA_BLOCKED | 0x1a | PATH_CHALLENGE |
0x18 | NEW_CONNECTION_ID | 0x1b | PATH_RESPONSE |
0x19 | RETRY_CONNECTION_ID | 0x1e | HANDSHAKE_DONE |
В приведенной выше таблице нам нужно проанализировать только 8 типов STREAM кадров 0x08-0x0f, чтобы понять принцип реализации Streamflow. Естественно, мы также поймем, как решается блокировка начала строки. Stream Frame используется для передачи HTTP-сообщений. Его формат следующий:
Видно, что три поля в заголовке Stream Frame выполняют функции мультиплексирования, упорядочения потоков байтов и двоичного разделения на уровне сегмента сообщения, включая:
Вам может быть интересно, почему существует 8 типов Stream Frame? Это связано с тем, что восемь типов 0x08-0x0f на самом деле состоят из 3 двоичных битов и реализуют следующую комбинацию из 3 битов флагов:
Потоковые данные не хранят HTTP-сообщения напрямую, поскольку HTTP3 также должен реализовывать отправку данных на сервер, настройку приоритета веса, управление потоком и другие функции, поэтому кадр HTTP3 сначала сохраняется в потоковых данных:
Среди них «Длина» определяет длину HTTP-сообщения, а поле «Тип» (обратите внимание, что младшие 2 бита имеют специальное назначение, которое будет подробно описано в главе QPACK) содержит следующие типы:
Подводя итог, QUIC Stream Frame определяет упорядоченный поток байтов, и передача между несколькими потоками не имеет требований по времени. Таким образом, HTTP-сообщения реализуют истинное мультиплексирование на основе QUIC Stream, и проблема блокировки начала строки естественным образом решается. . Решено.
Наконец, давайте посмотрим на метод кодирования HTTP-заголовка, который должен решать еще одну проблему блокировки начала строки.
Подобно методу кодирования HPACK в HTTP2, QPACK в HTTP3 также использует статические таблицы, динамические таблицы и кодировку Хаффмана:
(Изображение см.:https://www.oreilly.com/content/http2-a-new-excerpt/)
Давайте сначала посмотрим на изменения в статической таблице. На приведенном выше рисунке метод GET сопоставлен с номером 2, что достигается путем жесткого кодирования уровней реализации протокола клиента и сервера. В HTTP2 имеется 61 статическая запись:
В QPACK это число увеличивается до 98 записей статической таблицы, как показано в массиве ngx_htt_v3_static_table в Nginx:
Вы также можете найти полную статическую таблицу HTTP3 здесь. Для кодирования Хаффмана и целых чисел QPACK мало чем отличается от HPACK, но методы кодирования и декодирования динамических таблиц сильно отличаются.
Так называемая динамическая таблица означает, что элементы заголовка, не включенные в статическую таблицу, добавляются в динамическую таблицу при их первом появлении. Таким образом, для последующей передачи используется только один номер, что значительно повышает эффективность кодирования. Поэтому динамическая таблица, естественно, является последовательной. Если при первом запросе произойдет потеря пакета, последующие запросы обязательно будут заблокированы при декодировании заголовка HPACK!
Как QPACK решает проблему блокировки начала строки? Фактически, QPACK независимо передает кодирование и декодирование динамической таблицы в одностороннем потоке. Только когда динамическая таблица в одностороннем потоке успешно закодирована, принимающая сторона может декодировать индекс динамической таблицы в HTTP-сообщении. двусторонний поток.
Мы также представили концепции одностороннего и двустороннего потока. Не волнуйтесь, на самом деле это очень просто. Односторонний означает, что только один конец может отправлять сообщения, а двусторонний означает, что оба конца могут отправлять сообщения. Помните заголовок кадра потока QUIC в предыдущем разделе? У идентификатора потока есть своя тайна. Помимо идентификации потока, его младшие два бита также могут выражать следующие комбинации:
Таким образом, если идентификатор потока равен 0, 4, 8 или 12, это двунаправленный поток, инициируемый клиентом (HTTP3 не поддерживает двунаправленный поток, инициированный сервером), который используется для передачи HTTP-запросов и ответов. Односторонний поток имеет множество применений, поэтому перед данными у него есть дополнительное поле «Тип потока»:
Тип потока имеет следующие значения:
Поскольку потоки HTTP3 передаются не по порядку, если закодированный поток, отправленный первым, поступает позже, заголовок QPACK в двунаправленном потоке не может быть декодирован. В это время двунаправленный поток, передающий HTTP-сообщения, перейдет в состояние блокировки блока (два конца могут быть). определить метод обработки блокировки потока через управляющий кадр).
В заключение прокомментируйте содержание этой статьи.
Определение соединений на основе четверок не подходит для сети IoT следующего поколения. HTTP3 создает концепцию идентификатора соединения для реализации миграции соединения. Интегрируя транспортный уровень и уровень представления, он не только сокращает время установления связи, но и шифрует большую часть данных. поля транспортного уровня, улучшая сетевую безопасность.
HTTP3 обеспечивает надежность соединения на уровне пакетов, реализует упорядоченные потоки байтов на уровне кадров QUIC и реализует семантику HTTP на уровне кадров HTTP3. Это полностью решает проблему блокировки начала строки и действительно реализует многопутевую передачу. уровень приложения.
QPACK использует независимые односторонние потоки для передачи информации динамического табличного кодирования и декодирования соответственно. Таким образом, потоки, которые передают HTTP-сообщения не по порядку и одновременно, не будут вызывать блокировку начала строки, а также могут значительно сжимать размер. HTTP-заголовок на основе времени.
В следующей статье я расскажу, как создать веб-сервис HTTP3 на основе Nginx.