Pull to refresh
153.21
AvitoTech
У нас живут ваши объявления

Ультимативный гайд по HTTP. HTTP/1.1 vs HTTP/2

Level of difficultyEasy
Reading time6 min
Views25K

Привет! Я Ивасюта Алексей, техлид команды Bricks в Авито в кластере Architecture, а это мой цикл статей о протоколе HTTP. В предыдущей части я рассказал о работе Cookies и механизме CORS. Теперь мы узнаем, какие нововведения в протокол привнесла версия HTTP/1.1 и чем она отличается от версии HTTP/2.

Нововведения в HTTP/1.1

Версия протокола HTTP/1.1 появилась в 1999 году. Это была первая стандартизированная версия. С тех пор работать с протоколом стало намного удобнее.

Новые методы в этой версии:

  • PUT заменяет все текущие представления сущности данными запроса. Например, в блоге можно заменить данные поста, который ранее был опубликован;

  • DELETE удаляет указанную сущность;

  • OPTIONS описывает параметры соединения с ресурсом;

  • TRACE проверяет обратную связь по пути к целевому ресурсу, предоставляет полезный механизм для отладки запроса.

Позже добавили ещё два метода: 

  • CONNECT устанавливает «туннель» к серверу, определённому по ресурсу.

  • PATCH частично изменяет указанную сущность данными из запроса.

Еще одним нововведением стало кеширование запрашиваемых ресурсов на стороне клиента. При следующем запросе они отдаются сразу из кеша, а время на загрузку сокращается.

Виртуальные хосты

До появления этого механизма на одном IP-адресе можно было располагать только один сайт. Стандартизированного способа разместить несколько сайтов на одной машине не было. Теперь появился обязательный заголовок Host. Он указывает на домен, с которого пришел запрос на веб-сервер. Сервер определяет хост по этому заголовку и решает, какие данные отправить клиенту.

Например, если запрос уходит с домена example.com, нужно добавить заголовок Host: example.com.

POST /path HTTP/1.1
Host: example.com
Content-Type: text/plain; charset=utf-8
Content-Length: 4

test

keep-alive

Чтобы передать данные по протоколу HTTP, надо установить TCP/IP1 соединение между клиентом и сервером. Оно устанавливается перед каждым запросом, а после выполнения запроса — закрывается. Эта операция требует ресурсов процессора на сервере и занимает время. Если сайтом пользуется несколько сотен человек или на странице загружаются несколько ресурсов — это незаметное явление. Но если сайтом начнут пользоваться миллионы пользователей, сервер не справится с нагрузкой, надо будет ставить железо помощнее. То же самое произойдет, если сайт сложный, с сотнями ресурсов. Пользователи будут долго ждать загрузку страниц.

Эту проблему пытались решить еще в версии протокола 1.0, использую специальное расширение keep-alive, которое позволяло создавать постоянные соединения. Такие соединения не закрываются после первого запроса и остаются открытыми для нескольких последующих. Так за одно соединение можно запросить несколько ресурсов, не перегрузить сервер и ускорить загрузку страниц.

Для того, чтобы механика работала, клиент должен был отправить в запросе к серверу заголовок Connection: keep-alive. Сервер же в ответе на запрос также должен был добавить этот заголовок. В таком случае, клиент будет использовать созданное TCP/IP соединение для отправки последующих запросов до тех пор, пока в запросе или ответе не будет передан заголовок Connection: close.

В HTTP/1.1 этот подход стандартизировали и все запросы по умолчанию стали keep-alive, без необходимости передавать дополнительные заголовки.

Пересылка частями (chunked)

Иногда серверу нужно передать много данных или данные, неизвестного размера (например, при потоковом воспроизведении аудио или видео). Кажется, что самый простой вариант — дождаться полной загрузки данных в оперативную память сервера и после этого отправить их клиенту. Но тут мы сталкиваемся с двумя проблемами:

  1. Данные можно будет отправить только после их полной загрузки. Это ломает концепцию потокового воспроизведения.

  2. Запросы к серверу от каждого клиента будут задействовать определённый размер оперативной памяти и быстро израсходуют физические лимиты на сервере.

В новой версии протокола проблему решили: ввели механизм потоковой передачи данных небольшими частями. При стандартной схеме работы сервер присылает клиенту весь ответ целиком, который упрощенно выглядит примерно так:

HTTP/1.1 200 OK

test

Если включить потоковую передачу, данные передаются небольшими кусочками — чанками. Длина чанка зависит от настроек сервера. В ответе на запрос сервер присылает заголовок Transfer-Encoding со значением chunked. При этом в теле ответа перед каждым чанком указывается его длина в байтах, а с новой строки — данные чанка. Когда передача данных заканчивается, последним присылается чанк нулевой длины. Упрощенный ответ от сервера может выглядеть так:

HTTP/1.1 200 OK
Transfer-Encoding: chunked

10
Long chunk
19
One more chunk data
0

Нововведения в HTTP/2

История второй версии протокола началась в 2009 году. Компания Google решила разрабатывать собственную надстройку над HTTP, чтобы повысить скорость работы и безопасности. Протокол назвали SPDY и развивали его 6 лет, а браузеры постепенно реализовывали его поддержку. В 2015 году в Google решили объединить SPDY и HTTP. Так появился HTTP/2.

Бинарные данные

В HTTP данные передаются серверу в формате текста. Это удобно для людей, нам легко воспринимать текстовую информацию. Можно легко просматривать содержимое запросов и ответов, вести отладку. Например, вручную писать текст запроса и отправлять его через telnet. Но в наше время нет необходимости в ручной отправке, а передача данных текстом — далеко не самый производительный вариант. 

HTTP/2 использует бинарный формат. Бинарные данные меньше размером, поэтому в таком формате скорость передачи и парсинга выше, а нагрузка на сеть — ниже. Браузеры с поддержкой HTTP/2 кодируют запросы в бинарный формат перед отправкой, а сервер обрабатывает запрос и декодирует.

Мультиплексирование

Современный сайт обычно работает так: отправляется первый GET-запрос → он возвращает клиенту HTML-страницу → она подключает дополнительные ресурсы: js-файлы, css-таблицы, картинки, шрифты. После загрузки всех (или почти всех) ресурсов сайт становится интерактивным для пользователя.

В HTTP/1.0 для загрузки каждого ресурса устанавливалось новое TCP/IP соединение. HTTP/1.1 принёс keep-alive, который позволил загружать множество ресурсов в рамках одного соединения. Это значительно увеличило производительность протокола. Однако, ресурсы загружаются последовательно (waterfall): нельзя получить следующий ресурс, пока не получен предыдущий. 

Когда запрос к ресурсу подвисает из-за сложностей с его получением, возникает проблема Head-Of-Line Blocking. Это означает, что зависший запрос блокирует отправку всех остальных, так как обработка идёт в порядке очереди. Новая структура передачи данных в бинарном формате дала возможность загружать несколько ресурсов параллельно.

Теперь вся информация при передаче бьётся на небольшие бинарные кусочки — фреймы. Они собираются в потоки, для каждого запрашиваемого ресурса создаётся отдельный. При этом все фреймы от разных потоков могут передаваться вперемешку в одном TCP/IP соединении. Принимающая сторона самостоятельно соберёт все фреймы из одного потока и обработает их. Также клиент теперь может прервать получение одного потока, не закрывая соединение.

Сжатие заголовков через HPACK

Раньше сжатие тела и заголовков происходило на уровне TLS. Это более низкий уровень по отношению к HTTP (микс транспортного уровня и уровня приложения). Он не знает, какой тип данных сжимает, и жмёт все через gzip при помощи алгоритма DEFLATE2

Позже в SPDY появился отдельный алгоритм сжатия заголовков, но он по-прежнему использовал DEFLATE внутри. Из-за него оба алгоритма были подвержены атакам типа CRIME3 и в результате злоумышленники получали авторизационные куки из сжатых заголовков. Поэтому многие пограничные сети, типа Cloudflare, блокировали сжатие заголовков, чтобы защитить пользователей от атак.

Во второй версии HTTP представили новый алгоритм сжатия заголовков HPACK4. Он не использует DEFLATE и заточен под эффективную защиту от CRIME-атак. С ним новая версия HTTP стала производительнее и безопаснее.

Приоритизация потоков

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

При отправке параллельных запросов на сервер клиент может расставить приоритеты запрашиваемых им ответов. Это делается присвоением каждому потоку веса от 1 до 256. Чем выше вес, тем выше приоритет. Потоки могут быть связаны с ресурсами на сервере: изображениями, CSS-файлами, HTML-страницами и другими. 

Сервер использует эту информацию, управляет потоками данных и определяет порядок их обработки. Например, он может начать обработку потока с более высоким приоритетом, даже если это не первый поток, который был отправлен. Помимо этого клиент может указывать зависимости между потоками. Тогда сервер создаёт дерево зависимостей, которое определяет порядок получения данных.

Server push

Это функция, которая позволяет серверу начать передачу ресурсов на клиент ещё до запроса.

Как это работает:

  1. Клиент отправляет запрос на сервер для загрузки страницы. Например, GET /index.html.

  2. Сервер анализирует запрос и определяет, какие ресурсы будут нужны для полной загрузки страницы. Например, CSS, JS и изображения.

  3. Сервер создаёт множество потоков данных и начинает отправлять эти ресурсы через Server Push на клиент, даже если он ещё не запросил их.

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

Для эффективной передачи ресурсов Server Push использует механизмы мультиплексирования и приоритизации потоков. Это уменьшает задержки при загрузке страницы, увеличивает скорость загрузки, улучшает пользовательский опыт.

Отмечу, что Server Push эффективен, только если сервер точно знает, какие ресурсы нужны для загрузки страницы. Иначе случится ненужная передача ресурсов и ухудшение производительности.

Насколько HTTP/2 лучше HTTP/1.1

Выход HTTP/2 кардинально изменил протокол и повысил его производительность и безопасность. Использование HTTP/2 может ускорить загрузку страницы на 30-50% по сравнению с HTTP/1.1. Но это может зависеть от многих факторов: размера файлов, их количества и скорости соединения.

Полезные ссылки

  1. Основы TCP/IP

  2. Алгоритм сжатия DEFLATE

  3. CRIME атаки

  4. Спецификация RFC 7541 про HPACK

Предыдущая статья: Как заонбордиться тимлиду — первые 90 дней на новой работе

Tags:
Hubs:
Total votes 9: ↑7 and ↓2+7
Comments10

Articles

Information

Website
avito.tech
Registered
Founded
2007
Employees
5,001–10,000 employees
Location
Россия