Просто о том, чем отличаются 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х рукопожатий, 1 рукопожатие для установления 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 и тд, но стоит ли этим загружать новичков?..
ссылка на оригинал статьи https://habr.com/ru/articles/739166/
Добавить комментарий