HTTP/2: streams и мультиплексирование

HTTP/2 сохраняет семантику HTTP, но заменяет текстовое HTTP/1.1 framing бинарными фреймами. Несколько логических streams делят одно TCP-соединение: HEADERS и DATA разных запросов могут чередоваться. Это убирает HOL blocking HTTP/1.1 между ответами, но не отменяет порядок доставки TCP.

Зачем это на интервью

Сильный ответ не сводится к «HTTP/2 быстрее». Он называет выигрыш — меньше соединений и независимые HTTP-стримы — и ограничения: packet loss на одном TCP connection, flow-control, CPU на TLS/HPACK, прокси и неверно настроенные лимиты.

Минимум для E4

  • Отличать connection, stream, message и frame.
  • Объяснять, что stream имеет идентификатор и состояние, а фрейм — единицу передачи.
  • Знать назначение SETTINGS, HEADERS, DATA, WINDOW_UPDATE, RST_STREAM и GOAWAY.
  • Понимать, что HTTP/2 требует TLS в браузерной практике, хотя протокол этого не делает обязательным.

Клиент и сервер обмениваются SETTINGS в начале соединения. MAX_CONCURRENT_STREAMS ограничивает одновременно активные streams, а flow-control window ограничивает объём DATA, который отправитель может послать до WINDOW_UPDATE. Это механизм защиты получателя от переполнения, а не rate limiting пользователя.

Углубление для E5/Senior

HPACK сжимает headers через статическую и динамическую таблицы. Динамическая таблица — состояние соединения, поэтому декодер обязан ограничивать размеры и применять настройки до обработки. Нельзя логировать или считать секреты безопасными лишь потому, что заголовок «сжат»: TLS защищает канал, но token всё равно может попасть в trace/metrics.

Мультиплексирование меняет форму перегрузки: один большой stream способен занимать flow-control window или доступную полосу, а потерянный TCP segment задержит последующие байты всех streams. Priority RFC 7540 исторически плохо интероперабельна; не стройте SLO на её предположениях. Для graceful drain сервер посылает GOAWAY с последним обработанным stream ID, клиент открывает новое соединение для более новых streams.

Ключевые понятия

  • Frame — бинарный блок протокола; message — request/response; stream — двунаправленный логический канал.
  • Multiplexing — interleaving фреймов разных streams в одном соединении.
  • Flow control — кредитный механизм на DATA; он существует на stream и connection уровне.
  • HPACK — сжатие HTTP headers со статической и динамической таблицами.
  • GOAWAY — сигнал прекращения создания новых streams с возможностью дочистить уже принятые.

Типовые вопросы

  1. Что именно устраняет HTTP/2?
    • Прикладную блокировку порядка ответов HTTP/1.1: маленький готовый ответ может идти между DATA другого stream.
  2. Почему loss всё ещё влияет на все streams?
    • TCP доставляет байты в строгом порядке; потерянный сегмент останавливает выдачу последующих байтов приложению.
  3. Зачем нужен flow control?
    • Чтобы получатель дозировал буферизацию DATA. Это не замена лимиту запросов или fairness между tenants.
  4. Когда использовать RST_STREAM, а не закрывать connection?
    • Когда ошибка относится к одному запросу: отмена stream не должна обрывать здоровые соседние requests.
  5. Как безопасно перезапустить backend?
    • Послать GOAWAY, перестать принимать новые streams, дождаться in-flight до deadline и затем закрыть connection.
  6. Почему header compression требует ограничений?
    • Большие или специально подобранные headers расходуют CPU/память декодера; нужны лимиты полей, таблицы и размера списка headers.

Практика

  • Снимите HTTP/2-сеанс через curl --http2 -v; критерий: найдены negotiated protocol, stream IDs и переиспользование connection.
  • Отмените один долгий запрос контекстом; критерий: сервер освобождает работу этого stream, соседний запрос на том же connection завершается успешно.
  • Проведите graceful shutdown HTTP/2-сервера; критерий: новые streams получают новое соединение, принятые завершаются или получают документированную deadline-ошибку.

Частые ошибки и ловушки

  • Приписывать HTTP/2 устранение TCP HOL blocking.
  • Считать MAX_CONCURRENT_STREAMS глобальным rate limit или не учитывать его в client pool.
  • Закрывать всё соединение при отмене одного request.
  • Не задавать max header list size и лимиты тела, надеясь только на HPACK.

Связанные темы

HTTP и Web · HTTP/1.1: соединения · HTTP/3 и QUIC · RPC и gRPC · Наблюдаемость

Источники

  • RFC 9113, HTTP/2.
  • RFC 7541, HPACK: Header Compression for HTTP/2.
  • RFC 9110, HTTP Semantics.
  • Go documentation: net/http HTTP/2 support and x/net/http2.