HTTP/1.1: соединения и ограничения
HTTP/1.1 обычно использует одно TCP-соединение для нескольких последовательных request/response обменов. Persistent connection уменьшает цену TCP/TLS handshake, но порядок байтов в TCP и порядок ответов HTTP/1.1 создают очереди: медленный ранний ответ может задержать следующий.
Зачем это на интервью
Нужно уметь объяснить, почему «keep-alive включён» не означает отсутствия latency-проблем, как выбрать размер connection pool и почему прокси обязан правильно обработать границы сообщений. Это базис для осмысленного перехода к HTTP/2 и HTTP/3.
Минимум для E4
- Знать, что HTTP/1.1 persistent connections включены по умолчанию, если не указан
Connection: close. - Отличать TCP-соединение от HTTP-запроса и понимать последовательность ответов.
- Объяснять head-of-line blocking в HTTP/1.1 и назначение нескольких соединений.
- Ограничивать idle connections, время чтения header/body и число одновременных запросов.
Границу тела определяют Content-Length, Transfer-Encoding: chunked либо закрытие соединения в допустимых сценариях. Одновременное наличие Content-Length и Transfer-Encoding — опасный сигнал: intermediaries должны применять правила RFC, иначе возможен request smuggling. chunked — framing HTTP/1.1, не свойство payload и не «потоковый JSON».
Углубление для E5/Senior
HTTP pipelining разрешал отправить несколько запросов до получения ответов, но ответы всё равно должны идти в порядке запросов. Из-за неправильной реализации посредников и блокировки он практически не используется браузерами. Клиенты обходили проблему параллельными TCP-соединениями, но это увеличивает handshake, congestion control state, FD и давление на upstream.
Connection pool — очередь с ограниченными ресурсами. Слишком малый pool создаёт wait time до отправки; слишком большой перегружает upstream и скрывает отсутствие backpressure. Измеряйте connection acquisition latency, in-flight requests, reuse ratio, handshake, ошибки и p99 отдельно для клиента и сервера. Таймауты должны покрывать acquire, connect, TLS, header и полный request deadline.
Ключевые понятия
- Keep-alive/persistent connection — повторное использование TCP-соединения для нескольких обменов.
- HOL blocking — задержка готовой работы за более ранней работой в одной очереди.
- Pipelining — несколько отправленных подряд запросов без ожидания ответа; порядок ответов остаётся строгим.
- Chunked transfer coding — способ определить конец тела при неизвестной длине; каждый chunk имеет размер в hex.
- Request smuggling — рассинхронизация границ запроса между прокси и origin.
Типовые вопросы
- Сколько запросов можно обслужить на keep-alive соединении?
- Много последовательно; сервер и клиент задают свои лимиты/idle timeout. Это не означает одновременную независимую обработку ответов на проводе.
- Почему браузер открывал несколько соединений к origin?
- Чтобы обойти HOL blocking HTTP/1.1 и получить параллелизм, ценой лишних TCP/TLS состояний.
- Зачем
Content-Length?- Он задаёт точную границу тела и позволяет reuse соединения; неверный размер нарушает framing следующего сообщения.
- Чем chunked отличается от compression?
- Chunked определяет передачу и конец тела, compression (
Content-Encoding) преобразует representation; их нельзя смешивать.
- Chunked определяет передачу и конец тела, compression (
- Почему timeout idle connection не равен deadline запроса?
- Idle timeout закрывает неиспользуемый socket; deadline ограничивает конкретную работу, включая ожидание pool и ответ.
- Почему нельзя просто отключить keep-alive при ошибках?
- Это маскирует bug и кратно увеличивает handshake/ephemeral ports; сначала надо проверить framing, таймауты и lifecycle body.
Практика
- Запустите slow endpoint и быстрый endpoint через одно HTTP/1.1 соединение; критерий: в trace видно, что быстрый ответ задержан порядком, и описан обход.
- Отправьте корректный chunked response и проверьте его
curl --raw; критерий: клиент получает тело, а соединение безопасно переиспользуется. - Настройте Go
http.Transport; критерий: заданыMaxIdleConns,MaxConnsPerHost, dial/TLS/header timeouts, а тест доказывает закрытие response body.
Частые ошибки и ловушки
- Считать HTTP/1.1 «один запрос на одно соединение» или считать keep-alive неограниченным ресурсом.
- Не закрывать
resp.Body, из-за чего соединение не возвращается в pool. - Давать frontend и backend разную трактовку
Content-Length/Transfer-Encoding. - Выбирать pool по CPU, игнорируя лимиты upstream, FD и очередь ожидания.
Связанные темы
HTTP и Web · HTTP: запрос и ответ · HTTP/2: streams · Linux и сети · Наблюдаемость
Источники
- RFC 9112, HTTP/1.1, sections on message framing and persistent connections.
- RFC 9110, HTTP Semantics.
- PortSwigger Web Security Academy: HTTP request smuggling.
- Go documentation:
net/httpandhttp.Transport.