HTTP/2 как транспорт
HTTP/2 как транспорт gRPC: даёт мультиплексирование (один запрос не блокирует другие), сжатие заголовков (HPACK), бинарный формат (быстрее парсинга) и стриминг (server/client/bidirectional). Решает проблему head-of-line blocking HTTP/1.1.
Введение: Эволюция веб-протокола
Представьте, что вы стоите в очереди в супермаркете. В старой очереди (HTTP/1.1) есть одно капризное правило: пока первый человек не расплатится и не уйдёт, второй не может даже подойти к кассе. Если первый долго выбирает сдачу — очередь стоит. Если нужно передать десять человек — они будут идти строго один за другим.
В новой очереди (HTTP/2) правило другое. Несколько человек могут подходить к кассе одновременно. Пока один расплачивается, второй может задать вопрос, третий — показать бонусную карту. Всё параллельно, всё быстрее.
HTTP/1.1 — это протокол, на котором построен современный веб и большинство REST API. Но у него есть недостатки: каждое соединение обрабатывает один запрос за раз, заголовки не сжимаются, данные передаются в текстовом виде.
HTTP/2 — это следующая версия протокола, которая решает эти проблемы. gRPC выбрал HTTP/2 в качестве транспорта, потому что он даёт мультиплексирование, сжатие заголовков, бинарный формат и стриминг — всё то, что нужно для высокопроизводительных API.
HTTP/2 (Hypertext Transfer Protocol version 2) — это мажорное обновление протокола HTTP, выпущенное в 2015 году. Он сохраняет семантику HTTP (методы, статусы, заголовки, URL), но полностью меняет то, как данные передаются по сети.
HTTP/1.1 vs HTTP/2: Ключевые отличия
| Характеристика | HTTP/1.1 | HTTP/2 |
|---|---|---|
| Формат | Текстовый (человеко-читаемый) | Бинарный |
| Соединения | Один запрос → одно соединение | Одно соединение → много потоков |
| Заголовки | Текстовые, без сжатия | Сжатые (HPACK) |
| Блокировка | Head-of-line blocking (HOL) | Нет (мультиплексирование) |
| Server Push | Нет (только через SSE/WebSockets) | Да (экспериментально) |
| Приоритеты запросов | Нет | Да |
| Шифрование | Опционально (HTTPS) | Рекомендовано (HTTP/2 + TLS) |
Проблемы HTTP/1.1, которые решил HTTP/2
Проблема 1: Head-of-line blocking (HOL)
В HTTP/1.1 каждое соединение обрабатывает один запрос за раз. Запросы выстраиваются в очередь.
sequenceDiagram
participant Client
participant Server
Client->>Server: Запрос 1 (медленный)
Note over Server: Обработка 1... (1 сек)
Server-->>Client: Ответ 1
Client->>Server: Запрос 2
Note over Server: Обработка 2 (0.1 сек)
Server-->>Client: Ответ 2
Проблема: Быстрый запрос 2 ждёт, пока завершится медленный запрос 1.
Решение HTTP/2: Мультиплексирование — несколько потоков в одном соединении.
sequenceDiagram
participant Client
participant Server
Client->>Server: Запрос 1 (поток 1)
Client->>Server: Запрос 2 (поток 2)
Note over Server: Обработка 1 (1 сек)
Note over Server: Обработка 2 (0.1 сек)
Server-->>Client: Ответ 2 (поток 2)
Server-->>Client: Ответ 1 (поток 1)
Результат: Запрос 2 получает ответ, не дожидаясь запроса 1.
Проблема 2: Множество соединений
Чтобы обойти HOL, браузеры открывают 6-8 параллельных соединений к одному домену.
Домен api.example.com
├── Соединение 1: запрос A
├── Соединение 2: запрос B
├── Соединение 3: запрос C
├── Соединение 4: запрос D
├── Соединение 5: запрос E
└── Соединение 6: запрос FПроблема: Каждое соединение требует ресурсов (память, TCP handshake, TLS handshake).
Решение HTTP/2: Одно соединение, много потоков.
Проблема 3: Несжатые заголовки
Каждый HTTP/1.1 запрос содержит заголовки, которые могут быть большими (иногда до нескольких килобайт). И они повторяются в каждом запросе.
GET /users/123 HTTP/1.1
Host: api.example.com
User-Agent: Mozilla/5.0
Accept: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Cookie: session_id=abc123Проблема: Много повторяющихся данных в каждом запросе.
Решение HTTP/2: Сжатие заголовков HPACK (словарь повторяющихся значений).
Проблема 4: Текстовый формат
HTTP/1.1 передаёт данные в текстовом виде (ASCII).
GET /users/123 HTTP/1.1
Host: api.example.comПроблема: Текст избыточен. “GET” можно было бы закодировать одним байтом, а не тремя.
Решение HTTP/2: Бинарный формат. Парсить байты быстрее, чем текст.
Ключевые особенности HTTP/2
1. Бинарный протокол
HTTP/1.1 передаёт текст. HTTP/2 передаёт бинарные кадры (frames).
Структура кадра:
| Длина (3 байта) | Тип (1 байт) | Флаги (1 байт) | Идентификатор потока (4 байта) | Данные |
|---|
Типы кадров:
| Тип | Назначение |
|---|---|
| DATA | Передача данных (тело ответа) |
| HEADERS | Передача заголовков |
| PRIORITY | Установка приоритета потока |
| RST_STREAM | Сброс потока (ошибка или отмена) |
| SETTINGS | Настройки соединения |
| PUSH_PROMISE | Server Push (объявление будущего ресурса) |
| PING | Проверка соединения |
| GOAWAY | Завершение соединения |
2. Мультиплексирование (Multiplexing)
Одно TCP соединение может передавать несколько независимых потоков одновременно.
graph TD
subgraph "Одно TCP соединение"
S1[Поток 1: запрос A]
S2[Поток 2: запрос B]
S3[Поток 3: запрос C]
S4[Поток 4: запрос D]
end
Что это даёт:
- Нет head-of-line blocking
- Нужно меньше соединений (экономия ресурсов)
- Лучшее использование пропускной способности
3. Сжатие заголовков (HPACK)
Заголовки сжимаются с использованием статического и динамического словарей.
Статический словарь (61 общий заголовок):
| Индекс | Заголовок | Значение |
|---|---|---|
| 2 | :method | GET |
| 3 | :method | POST |
| 4 | :path | / |
| 5 | :path | /index.html |
| 6 | :scheme | http |
| 7 | :scheme | https |
| 8 | :status | 200 |
| 9 | :status | 204 |
Динамический словарь: Запоминает заголовки, которые встречались в этом соединении.
Пример сжатия:
# Оригинальные заголовки (200 байт)
:method: GET
:path: /users/123
:scheme: https
user-agent: Mozilla/5.0
authorization: Bearer abc123
accept: application/json
# После сжатия HPACK (50 байт)
# :method и :path — ссылки на статический словарь
# authorization — сохранён в динамическом словаре4. Server Push (экспериментально)
Сервер может отправить ресурсы, не дожидаясь запроса клиента.
sequenceDiagram
participant Client
participant Server
Client->>Server: GET /index.html
Server-->>Client: PUSH_PROMISE (style.css)
Server-->>Client: PUSH_PROMISE (script.js)
Server-->>Client: index.html
Server-->>Client: style.css
Server-->>Client: script.js
Когда полезно: HTML страница, которая ссылается на CSS, JS, изображения. Сервер отправляет их вместе с HTML.
В gRPC: Server Push используется редко, но теоретически возможен.
5. Приоритеты потоков
Клиент может указать важность каждого потока.
graph TD
A[Корень] --> B[Поток 1: 40%]
A --> C[Поток 2: 30%]
A --> D[Поток 3: 20%]
A --> E[Поток 4: 10%]
Пример: В браузере запрос HTML имеет высший приоритет, CSS и JS — средний, изображения — низкий.
Как gRPC использует HTTP/2
Заголовки gRPC
Каждый gRPC вызов использует специальные HTTP/2 заголовки.
:method: POST
:path: /example.UserService/GetUser
:scheme: https
content-type: application/grpc
grpc-timeout: 10S
grpc-encoding: gzip
authorization: Bearer token123| Заголовок | Значение |
|---|---|
:method | Всегда POST (даже для запросов чтения) |
:path | /{package}.{service}/{method} |
content-type | application/grpc (или application/grpc+proto) |
grpc-timeout | Таймаут вызова (10S — 10 секунд) |
grpc-encoding | Кодирование (сжатие) тела |
gRPC кадры поверх HTTP/2
gRPC оборачивает protobuf сообщения в HTTP/2 DATA кадры.
HTTP/2 DATA frame
├── Флаг END_STREAM (последнее сообщение)
└── Данные (сжатый protobuf + 5-байтовый префикс)Префикс gRPC (5 байт):
| Байт | Назначение |
|---|---|
| 1 | Флаг сжатия (0 = нет, 1 = есть) |
| 2-5 | Длина сообщения (big-endian, 4 байта) |
gRPC статус в трейлерах
В отличие от HTTP, где статус в заголовке, gRPC передаёт статус в трейлерах (заголовках после тела).
# После тела ответа
grpc-status: 0
grpc-message: OK| grpc-status | Значение |
|---|---|
| 0 | OK |
| 1 | Canceled |
| 2 | Unknown |
| 3 | InvalidArgument |
| 4 | DeadlineExceeded |
| 5 | NotFound |
| … | … |
HTTP/2 и производительность
Сравнение: HTTP/1.1 + REST vs HTTP/2 + gRPC
Сценарий: Получить 100 пользователей (каждый по одному запросу).
HTTP/1.1 + REST:
- 100 TCP соединений (или 6 соединений × 17 “пакетов”)
- 100 TLS handshake (если HTTPS)
- Head-of-line blocking
- Заголовки повторяются 100 раз
HTTP/2 + gRPC:
- 1 TCP соединение
- 1 TLS handshake
- Нет HOL
- Сжатые заголовки (HPACK)
Результат: gRPC может быть в 5-10 раз быстрее для большого количества маленьких запросов.
HTTP/2 и безопасность
HTTP/2 без шифрования (h2c)
HTTP/2 может работать без TLS (h2c — HTTP/2 cleartext), но браузеры его не поддерживают. В gRPC обычно используется HTTP/2 + TLS.
TLS особенности HTTP/2
- ALPN (Application-Layer Protocol Negotiation): Клиент и сервер договариваются, что будут использовать HTTP/2, а не HTTP/1.1
- SNI (Server Name Indication): Клиент указывает, к какому домену подключается (важно для виртуального хостинга)
Ограничения HTTP/2
| Ограничение | Значение |
|---|---|
| Максимум потоков | ~100 000 (настраивается) |
| Максимум фреймов в полёте | Зависит от window size (настраивается) |
| Server Push | Плохо поддерживается, сложно отлаживать |
| Head-of-line blocking на TCP уровне | При потере пакета, все потоки ждут |
Важно: HTTP/2 решает HOL на уровне запросов, но не решает HOL на уровне TCP. Если TCP пакет потерян, все потоки ждут его повторной передачи. HTTP/3 (на базе QUIC) решает и эту проблему.
HTTP/2 vs HTTP/3
| Характеристика | HTTP/2 | HTTP/3 |
|---|---|---|
| Транспорт | TCP | QUIC (UDP-based) |
| HOL на уровне TCP | Есть | Нет |
| Шифрование | TLS 1.2/1.3 | TLS 1.3 (всегда) |
| Поддержка gRPC | Да (стабильно) | Экспериментально |
gRPC уже экспериментирует с HTTP/3 (gRPC-QUIC), но пока стандарт — HTTP/2.
Практические последствия для аналитика
Что нужно знать про HTTP/2 для gRPC
Одно соединение — много потоков. Не нужно пул соединений, как в HTTP/1.1.
Стриминг на уровне протокола. Server streaming, client streaming, bidirectional — нативные возможности HTTP/2.
Сжатие заголовков. Трафик заголовков минимален.
Требуется TLS для продакшена. Без TLS HTTP/2 работает, но не во всех средах.
Не все load balancers поддерживают HTTP/2. Некоторые “понимают” только HTTP/1.1 и разрывают соединение.
Советы по настройке
| Параметр | Рекомендация |
|---|---|
| Max concurrent streams | 1000-10000 (зависит от нагрузки) |
| Initial window size | 64KB-1MB (для больших стримов) |
| Keepalive | Включить (чтобы соединение не закрывалось) |
| Ping | Периодические проверки соединения |
Резюме для системного аналитика
HTTP/2 — транспорт gRPC. Он даёт мультиплексирование, сжатие заголовков, бинарный формат и стриминг.
Главное преимущество — мультиплексирование. Одно соединение обрабатывает много параллельных запросов. Нет head-of-line blocking на уровне запросов.
Бинарный протокол быстрее парсится и компактнее текстового.
HPACK сжимает заголовки. Использует статический и динамический словари.
gRPC использует POST для всех вызовов. Даже для получения данных (unary). Путь содержит сервис и метод:
/:service/:method.Статус gRPC передаётся в трейлерах, а не в заголовках.
Для продакшена нужен TLS. Браузеры не поддерживают HTTP/2 без TLS.