Просто о том, чем отличаются HTTP1, HTTP2 и HTTP3, а также почему HTTP3 ещё и QUIC. Статья для junior'ов, http-любознательных и готовящихся к собеседованиям.

я ожидаю ответов на собеседовании, а их...
я ожидаю ответов на собеседовании, а их...

В интернете немало хороших статей по теме, однако, как правило, вопрос рассматривается глубоко, подробно, многословно, часто требует знаний по теме. Начинающим IT'шникам, без понимания вопроса и бэкграунда, бывает сложно ухватить суть улучшений, понять какие проблемы были решены и почему они стали актуальны. Постараюсь упрощённо и коротко раскрыть вопрос.

Необязательное для темы и прочтения нытьё про собеседования

По долгу службы проводил собеседования с соискателями разного уровня, нередко в попытках вытянуть junior'ов задаю вопросы про отличие разных версий протокола HTTP и ещё ни разу не слышал хорошего ответа. Точнее ни разу не слышал хоть какого-то осмысленного ответа, максимум "что-то про использование соединений и шифрование".

Кандидаты в мидлы и сениоры тоже умудряются ничего толком не знать в вопросе, и даже если могут перечислить отличия, часто не могут толком пояснить суть изменений.

Главное

Причина появления версий 2 и 3 - скорость.

Скорость загрузки страницы в браузере. Скорость установления соединения. Скорость обмена данными между сервером и страницей. Скорость обмена данными между сервисами/микросервисами.

Что мешает HTTP1 работать быстро, в порядке значимости:

  • Блокировка соединения.

  • Время на установление соединения.

  • Объём обязательных данных.

Удобно что 3я версия появилась ровно по тем же причинам что и вторая и запоминать 2 набора причин не нужно.

Далее для HTTP1 мы будем иметь ввиду версию 1.1 и соединение с шифрованием, тк HTTP1.0 как и соединения без шифрования уже мягко говоря неактуальны.

Блокировка соединения

Head-of-Line Blocking или упростим до "блокировка соединения". Как происходит - у нас есть канал для передачи данных, мы отправили запрос в этот канал, ждём ответа, получили полностью ответ, отправили следующий запрос.

Представим что мы отправили запрос, а ответ требует долгих вычислений на стороне сервера - что произошло с нашим каналом? Он заблокирован. Мы должны дождаться ответа на отправленный запрос, перед тем как запросить новые данные — мы не можем дальше загружать страницу.

HTTP1 -> HTTP2

Первая версия протокола http требовала дожидаться получения ответа перед отправлением следующего запроса в рамках одного соединения. Во второй версии протокола - это исправили, соединение может использоваться без ожидания завершения уже отправленного запроса.

HTTP2 -> HTTP3/QUIC

Проблема блокировки была решена в версии 2 — но только на уровне http протокола. На транспортном уровне tcp она все еще есть в виде обязательного последовательного получения пакетов. Поэтому версию 3 собрали на протоколе udp, в которой этой особенности нет, и назвали это QUIC.

Визуализация

Выполнение запросов HTTP1

Выполнение запросов HTTP2

Хочу посмотреть в инспекторе сам

Посмотреть самостоятельно можно тут - http://www.httpvshttps.com. Сайт образец, любезно созданный Let's Encrypt, для визуализации различий. Спасибо, что он есть.

На видео порядок получения картинок для сайта. Линия - это одно соединение, серые засечки на линиях - это отправка запросов, зелёная полоска - это ожидание ответа, синяя - это получение контента.

На видео с версией 1 - чётко видна последовательность, отправка запроса, ожидание, получение данных. Чётко видно что все соединения практически синхронно блокируются и ждут. Причём линий у нас несколько, т.е. несколько соединений. Установление нескольких соединений - это первые попытки решить проблему блокировки для версии 1.

На видео с версией 2 - соединение одно и запросы(засечки) отправляются в него сразу пачками. Соединение практически не простаивает - нет "зелёного" ожидания. Загрузка страницы происходит быстрее, потому-что браузеру не надо ждать медленных ответов.

Всё равно не понял, нужен пример!

Представьте что у нас сайт с генератором мемов с красивыми шрифтами. Пользователь выбирает картинку, вводит текст, выбирает 7 шрифтов в чекбоксах и нажимает кнопку submit, происходит перезагрузка страницы. На странице 7 картинок <img src='mymeme.jpg?text=hello&font=22', и браузер в процессе отрисовки страницы, отправляет во все доступные нам в http1 коннекты запрос на эти картинки. Сервер начинает генерить картинки, создает в памяти пустую картинку, накладывает фон, грузит шрифт ... 100500 действий ... проходит много врмени, отдает картинку браузеру. Что происходит в это время в браузере - ничего, в худшем случае белый лист, тк все соединения заняты долго генерящимися картинками и получить css, js, xhr, svg чтобы отрисовать страницу до конца мы не можем.
В случае http2 мы отправляем запросы на долго генерящиеся мемы в соединение и не ждём, а отправляем запросы за другими данными, рисуем страницу и видим полностью готовую страницу с пустыми местами под мемы, которые лениво постепенно появляются.

Время на установление соединения

Дело в том что для того, чтобы передавать данные, клиенту и серверу надо договориться о том, как это будет происходить. Совершить своего рода рукопожатие - Handshake. То есть отправить некий вопрос и получить на него ответ, совершив полный "круг" обмена информацией.

Если при этом нам надо получить данные от сервера, с которым не было установлено соединение, например флаг о наличии обновлений - цифру 1 или 0, то для простейшей операции нам надо совершить N "кругов" обмена информацией = количество рукопожатий + запрос.

HTTP1 -> HTTP2

Для того чтобы установить шифрованное соединение и обменяться данными для http1 или http2 нам необходимо сделать от 2х до 3х рукопожатий. Одно рукопожатие для установления tcp соединения, 1 или 2 рукопожатия, в зависимости от версии протокола, для установления шифрованного соединения. Итого 2-3 рукопожатия.
Так где же улучшение в версии 2?

Возвращаемся к визуализации для первой версии. У каждой линии (соединения) есть желтый участок - это установление соединения, включая рукопожатия. То есть на каждое соединение - отдельный набор рукопожатий. В версии 2 - соединение одно.

http1 = кол-во соединений x кол-во рукопожатий / 1-6 x 2-3 = 2-18
http2 = кол-во рукопожатий / 2-3

HTTP2 -> HTTP3/QUIC

В третьей версии, поскольку собрали новый протокол QUIC, обо всём хорошо подумали и рукопожатия свели к одному. В один запрос упаковали установление соединения и установление шифрования.

Плюс в версии 3 при разрыве соединения не нужно устанавливать новое, то есть не будет повторных рукопожатий, так как используется уникальный идентификатор соединения.

http3/quic = const 1

Объём обязательных данных

Чтобы получить ответ из 1 символа, нам всё равно надо отправить HTTP заголовок в виде текста, в котором могут быть присоединены cookie, который может быть одинаковым для сотни запросов. Почему вопрос именно про заголовок? Потому-что - это не уникальные данные требующиеся для каждого запроса.

В данном случае объединим версии 2 и 3.

HTTP1 -> HTTP2 и HTTP3/QUIC

Для того, чтобы уменьшить объём по сравнению с первой версией, заголовки стали:

  • передавать в бинарном виде, а не текстом, как раньше - такой вид удобнее для машины и занимает меньше места;

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

Заключение

Всё указанное выше - это базовое описание изменений протокола http и причин этих изменений. Если читатель всё прекрасно понял и запомнил, есть смысл обратиться к более подробным статьям, которые потребуют прочтения ещё более подробных статей.

Для возмущенных профессионалов.

Я знаю про flow-control, 0-rtt, server push и тд, но стоит ли этим загружать новичков?..

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


  1. khe404
    06.06.2023 08:22

    Как интересно построена эволюция сетевых протоколов и форматов хранения данных:


    Очень часто пишут что различные протоколы и форматы "улучшились" благодаря тому что их перевели из текстового в бинарный формат.


    Если формат построен на UDP то как устроены ссылки на ранее посланные данные, если данные могли и не пройти.


    1. TheGast
      06.06.2023 08:22
      +2

      Тебе ответ о том, были данные или нет, всё-равно придёт (или не придёт, если пакет потерялся, но тогда будет timeout-event). Просто на транспортном уровне это будет несколько дешевле.


      1. khe404
        06.06.2023 08:22

        Ну, т.е. похоже что часть забот о том чтобы проследить доставлены ли данные переложили на протокол более высокого уровня. И основная выгода в том что последовательность пакетов данных может быть не принципиальна в случае с HTTP.


        1. bbc_69
          06.06.2023 08:22

          Подозреваю, что в случае стабильного соединения это всё равно будет в плюс.


          1. khe404
            06.06.2023 08:22

            Ниже в комментариях отметили что tcp как раз теряет эффективность на нестабильных каналах радиосвязи.
            И использование udp и новый протокол http позволит решать такие проблемы более эффективно, с учетом как раз особенностей интернета на мобильных устройствах.


            1. mayorovp
              06.06.2023 08:22

              Уточнение: tcp теряет эффективность на гибридных каналах связи.


              Если наш канал связи — куча оптики вокруг земного шара (высокий пинг, околонулевые потери), TCP использует компенсирует пинг увеличенным размером окна отправки и неплохо работает.


              Если наш канал связи — радиоканал (низкий пинг, высокие потери), то TCP не может поднять размер окна, но при низком пинге это и не нужно.


              А вот если наш канал связи состоит из радиоканала с последующей оптикой вокруг земного шара, то у нас высокий пинг и высокие потери, из-за чего у TCP и возникают проблемы.


              1. khe404
                06.06.2023 08:22

                Да, там в статье которую рекомендуют ниже вообще большой объем информации о том как работают каналы связи и где возникают потери и какие алгоритмы используются для их минимизации. (У оптики тоже есть пропускная способность, так что там тоже не все гладко).
                Вообще, протоколы обмена данными очень интересная вещь, и что поразительно — под капотом любых цифровых обменов лежит азбука Морзе точнее некий аналог.


    1. yrub
      06.06.2023 08:22
      +7

      сильно не вчитывайтесь, т.к. автор похоже слабо понимает о чём пишет или лепет из разных статьей с сильными сокращениями. http 1 открывал множество соединений потому что это сильно упрощало реализацию. http2 сервер стал на много сложнее и использует одно соединение для передачи фрагментов разных ресурсов (да и ещё с приоритетами). но с tcp есть проблема в мобильных сетях (особенно когда вы едете на машине) + он сильно привязан к железу - роутерам, свичам и т.д., по-этому реализовать разные механизмы управления скоростью передачи (контролем канала) сложно, в сам tcp протокол это встроено, но то что работает хорошо для проводной сети дома не очень подходит для мобильной. так что приходится это всё переизбирать и вешать на udp. поищите доклад тех директора vk если интересна тема


      1. khe404
        06.06.2023 08:22

        Да, пожалуй в Ваш комментарий суть вопроса открывает совсем с другой стороны.
        Статью Александра нашел, буду читать.


  1. meduza
    06.06.2023 08:22

    Первая версия протокола http требовала завершения запроса в соединении

    Если речь про HTTP/1.1 то это не правда ведь. В 1997 уже был RFC.


    1. mv28jam Автор
      06.06.2023 08:22
      +1

      Это про закрытие соединения. Если бы я написал требует закрытия соединения, то да.


      1. homm
        06.06.2023 08:22

        Вы очень витиевато написали. Как насчет:

        Первая версия протокола http требовала дожидаться получения ответа перед отправлением следующего запрос в рамках одного соединения.

        Формально это кстати неправда, но фактически к сожалению так и было.


        1. mv28jam Автор
          06.06.2023 08:22
          +1

          Спасибо, ваша формулировка лучше.

          Использую её, если не против.


  1. AntoineLarine
    06.06.2023 08:22

    На хабре есть отличные переоводы статей про HTTP/3 (один, два и три). После их прочтения некоторая часть лапши спадает с ушей. Особенно в части того, как все заживём. Спецификация HTTP/3 слишком сложна (грамотных реализаций мало, будет куча проблем неполной совместимости со стандартом и т.п.). Кроме того, груз легаси- серверов, клиентов и промежуточных устройств слишком велик, чтобы этот переход прошёл в обозримой перспективе. Это как IPv6: идея хорошая, но никак не взлетает из-за инерции рынка.


    1. homm
      06.06.2023 08:22
      +3

      Что вы понимаете под прохождением перехода? Клиент соединяется с сервером, если они оба поддерживают HTTP/3, всё переход прошел. Другой клиент не поддерживает? Ну так кто-то пользуется 0.9, если не жмёт. Какая разница?


    1. mv28jam Автор
      06.06.2023 08:22

      Ozon.ru использует третью версию, например.

      В целом есть статистика, например - https://w3techs.com/technologies/history_overview/site_element/all


    1. Layan
      06.06.2023 08:22

      Кроме того, груз легаси- серверов, клиентов и промежуточных устройств слишком велик, чтобы этот переход прошёл в обозримой перспективе.

      Кто-то жалуется на невозможность внедрения, а кто-то уже в проде использует по полной.


  1. homm
    06.06.2023 08:22
    +5

    Не стал читать статью по причине: неправильное использование мема.


  1. makarovpro
    06.06.2023 08:22

    Спасибо, полезная информация.