# теория · шаг 1 из 5
Что HTTP/2 меняет на самом деле
Коротко
HTTP/2 - это мультиплексирование в одном соединении плюс сжатие заголовков. Он снимает лимит на шесть соединений к домену.
- Выигрыш появляется не всегда: на чистой сети замер даёт 814 мс против 821 у шести соединений HTTP/1.1 - то есть поровну.
- Зато на сети с потерями шесть соединений начинают проигрывать: одна потеря тормозит только одно из них.
- Приёмы времён HTTP/1.1 - шардинг, спрайты, склейка бандлов - после включения мешают.
- Чего он не чинит: свой собственный head-of-line blocking на уровне TCP. Замер показывает его прямо.
Если знаешь, что мультиплексирование не отменяет очередь в TCP, - листай до «Теперь сам».
Сначала ответь сам
Страница тянет 30 файлов. Включаем HTTP/2 и ничего больше не трогаем. Насколько быстрее станет?
Стенд, задержка 100 мс, семь прогонов, медиана:
HTTP/1.1, шесть соединений 821 мс
HTTP/2, одно соединение 814 мс
Поровну. Мультиплексирование не ускоряет само по себе: шести соединений хватает, чтобы вытянуть тридцать файлов за то же время. Выигрыш HTTP/2 в другом - и проявится он на плохой сети, а не на хорошей.
На что это похоже
Шесть кассиров против одного конвейера. Пока покупателей тридцать, а очередь движется ровно, разницы почти нет: шесть касс справляются.
Разница появляется, когда у кого-то заминка. У шести касс встанет одна из шести - остальные пять работают. У конвейера заминка в начале останавливает всё, что за ней.
Так вот HTTP/2 - это конвейер. И именно поэтому дальше в главе речь пойдёт о том, чего он не чинит.
Механизм: фреймы вместо очереди
Второе, что даёт HTTP/2, - сжатие заголовков. В HTTP/1.1 каждый из тридцати
запросов тащит одинаковые User-Agent, Accept, Cookie: легко килобайт на
запрос. HTTP/2 передаёт повторы ссылкой на таблицу, которую обе стороны ведут
синхронно.
Правило
Включив HTTP/2, разбери костыли, придуманные ради обхода лимита в шесть соединений, - теперь они работают против тебя:
Браузер держит к одному домену не больше шести одновременных соединений - отсюда и костыли, придуманные, чтобы обойти этот предел:
- доменный шардинг (
img1.shop.ru,img2.shop.ru) - каждый лишний домен это отдельное TLS-рукопожатие и отдельная таблица заголовков; - спрайты (много мелких картинок, собранных в одну) и склейка бандлов (весь JavaScript в один файл) - правка одной строки инвалидирует в кеше весь склеенный файл;
- инлайн base64-картинок в CSS - раздувает файл, который иначе лежал бы в кеше отдельно, и плохо сжимается.
Порядок работ ровно такой: включил протокол, разобрал костыли, измерил. Если включить HTTP/2 поверх сборки под HTTP/1.1, выигрыш будет скромным - протокол честно ускорит то, что ему дали, а дали ему один двухмегабайтный бандл.
Разбор: где HTTP/2 начинает выигрывать
Тот же стенд, но с потерями на пути запросов:
HTTP/1.1, шесть соединений 1146 мс
HTTP/2, одно соединение 813 мс
Вот теперь разница есть, и взялась она не из мультиплексирования как такового. У шести соединений каждое ведёт свой контроль перегрузки (механизм TCP, который сам замедляет отправку, нащупывая скорость канала) и своё восстановление после потерь; потерянный пакет тормозит одно из шести, но соединений всего шесть, а файлов тридцать - и очередь наверстать не успевает.
Разбор: чего HTTP/2 не чинит
Теперь потери переносим на сторону сервера - туда, где идут сами данные. Семь прогонов, отсортированные времена:
| протокол | прогоны, мс |
|---|---|
| HTTP/1.1, шесть соединений | 1017 1120 1214 1237 1341 1420 1767 |
| HTTP/2, одно соединение | 1313 1413 1714 2021 5221 5268 5486 |
Медиана HTTP/2 хуже почти вдвое, а хвост уходит за пять секунд. Причина - TCP: он отдаёт данные приложению строго по порядку, и пока потерянный сегмент не доехал повторно, ядро держит всё, что пришло после него. Встают все тридцать потоков разом, включая те, чьи данные уже лежат в буфере.
Это head-of-line blocking на уровне транспорта. Внутри TCP его не починить - очерёдность часть его контракта. Отсюда и вырос QUICРазбирается в разделе 10, глава «HTTP/3 и QUIC»: Почему понадобился QUIC, следующая глава.
Что ломается без этого
Server push умер. Идея «отправим файлы до того, как их попросят» не пережила столкновение с кешем браузера: сервер не знает, что у клиента уже есть, и push регулярно слал байты в никуда. Chrome выключил поддержку в 2022 году, а nginx отвечает на директиву прямо:
[warn] the "http2_push" directive is obsolete, ignored
Замена - 103 Early Hints: бэкенд, зная, что ответ будет долгим, заранее отдаёт промежуточный ответ со ссылками, а браузер сам решает, что предзагрузить. nginx проксирует такие ответы с версии 1.29.0 (в стабильной ветке с 1.30.0):
early_hints on;
Приоритеты потоков практически не используются. Сложная схема зависимостей из первой редакции протокола оказалась неработоспособной и была выкинута; пришедшая ей на смену поддержана далеко не везде. Считай, что порядок отдачи решает браузер.
Зачем это в работе
Из замеров следует практический вывод, который редко пишут в статьях: включение HTTP/2 само по себе почти ничего не даёт на хорошей сети. Оно даёт две вещи: устойчивость к плохой сети до определённого предела и возможность разобрать костыли.
Поэтому оценивать эффект надо не «стало ли быстрее у меня в офисе», а по метрикам с реальных клиентов - и отдельно смотреть на мобильных, где потери есть всегда.
Теперь сам
Сайт перевели на HTTP/2, разобрали шардинг и разбили бандл на двадцать файлов. Метрики у десктопных клиентов не изменились, у мобильных стало хуже. Что произошло?
Ровно то, что на графике замера: у мобильных потери, и одно соединение с двадцатью потоками страдает от head-of-line blocking сильнее, чем прежние шесть. Разбиение бандла усилило эффект - файлов стало больше, и каждая потеря задерживает их все. Лечится это не откатом, а HTTP/3 рядом с HTTP/2: следующая глава.
Главное
HTTP/2 - мультиплексирование в одном соединении плюс сжатие заголовков. На чистой сети выигрыша против шести соединений HTTP/1.1 почти нет (замер: 814 против 821 мс), на сети с потерями он появляется. Костыли времён HTTP/1.1 - шардинг, спрайты, склейка - после включения мешают и разбираются следом. Чего протокол не умеет - победить очерёдность самого TCP: при потерях на стороне данных медиана HTTP/2 оказалась вдвое хуже шести соединений, а хвост ушёл за пять секунд. Server push мёртв, вместо него 103 Early Hints.
Комментарии
Пока нет комментариев. Будь первым!
Оставить комментарий