# теория · шаг 1 из 5
Что HTTP/2 меняет на самом деле
Коротко
HTTP/2 - это мультиплексирование в одном соединении плюс сжатие заголовков. Он снимает лимит на шесть соединений к домену.
- Выигрыш появляется не всегда: на чистой сети замер даёт 814 мс против 821 у шести соединений HTTP/1.1 - то есть поровну.
- На сети с потерями всё решает, где теряются пакеты. На пути запросов - HTTP/2 выигрывает, 813 мс против 1146. На пути данных - проигрывает, медиана 2021 мс против 1237: потерянный сегмент останавливает все потоки единственного соединения, а у шести соединений HTTP/1.1 - только одно из них.
Если знаешь, что мультиплексирование не отменяет очередь в 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 убирает саму причину - очередь TCP, - но и его меряют: на стенде следующей главы конкретная сборка проиграла обоим.
Главное
HTTP/2 объединяет потоки в одном TCP-соединении, поэтому потери на этом соединении могут задержать сразу несколько ответов. Проверяй эффект на типичных клиентах и сети. Результат одного стенда не определяет универсальный способ разбиения ресурсов или гарантированный выигрыш от смены протокола.
Комментарии
Пока нет комментариев. Будь первым!
Оставить комментарий