Connection management in HTTP/1.x

Управление соединением является ключевой темой HTTP: открытие и поддержка соединения оказывает значительное влияние на производительность веб-сайтов и веб-приложений. В HTTP/1.x имеются следующие модели: краткосрочные соединения, постоянные соединения и конвейерная обработка HTTP (HTTP pipelining).

В качестве транспортного протокола, обеспечивающего связь между клиентом и сервером, HTTP по большей части использует TCP. Это краткосрочные (short-lived) соединения: при каждой отправке запроса открывается новое соединение, которое закрывается после того, как ответ получен.

Такой модели присущи проблемы в отношении производительности: ресурсы приходится затрачивать на открытие каждого соединения TCP. Клиенту и сервером необходимо обмениваться несколькими сообщениями. При отправке каждого запроса приходится считаться с запаздыванием и пропускной способностью сети. Современным веб-страницам требуется выполнять множество (десятки) запросов для передачи необходимой информации, что делает данную модель неэффективной.

В HTTP/1.1 были созданы две новые модели. Модель постоянного соединения оставляет соединение открытым между последовательными запросами, экономя время, требуемое для открытия новых соединений. Модель конвейерной обработки HTTP делает следующий шаг - она позволяет отсылать несколько запросов подряд, не дожидаясь ответа, что существенно сокращает время ожидания в сети.

Compares the performance of the three HTTP/1.x connection models: short-lived connections, persistent connections, and HTTP pipelining.

Примечание: В HTTP/2 внесены дополнительные модели управления соединением.

Важно отметить, что управление соединением в HTTP применяется к соединению между двумя последовательными узлами, и является пошаговым (hop-by-hop) а не "конец-к-концу" (end-to-end). Модель, используемая для соединения клиента с его первым прокси, может отличаться от модели соединения между прокси и конечным сервером (или любым из промежуточных серверов). Заголовки HTTP, вовлечённые в определение модели соединения, типа HTTPHeader("Connection")}} и Keep-Alive (en-US), являются пошаговыми заголовками, значения которых могут изменяться промежуточными узлами.

Краткосрочные соединения (Short-lived connections)

Исходной моделью в HTTP, в HTTP/1.0 она же является моделью по умолчанию, являются краткосрочные соединения (short-lived connections). Для каждого HTTP запроса используется отдельное соединение; это означает, что "рукопожатие" TCP происходит перед каждым из запросов HTTP, идущих один за другим.

TCP-рукопожатие само по себе затратно по времени, но TCP-соединения приспособились справляются с этой нагрузкой, превращаясь в устойчивые (или тёплые) соединения. Краткосрочные соединения не используют это полезное свойство TCP, так что эффективность оказывается ниже оптимальной из-за того что передача осуществляется по новому, холодному соединению.

Данная модель является моделью по умолчанию в HTTP/1.0 (при отсутствии заголовка Connection, или когда его значением является close). В HTTP/1.1 такая модель используется только если заголовок Connection посылается со значением close.

Примечание: Если речь не идёт об очень старой, не поддерживающей постоянные соединения, системе, данную модель использовать нет смысла.

Постоянные соединения

Краткосрочные соединения имеют два больших недостатка: требуется значительное время на установку нового соединения, и то, что эффективность TCP-соединения улучшается только по прошествии некоторого времени от начала его использования (тёплое соединение). Для решения этих проблем была разработана концепция постоянного соединения (persistent connection), ещё до появления HTTP/1.1. Его также называют соединением keep-alive.

Постоянным называют соединение, которое остаётся открытым некоторый период времени и может быть использовано для нескольких запросов, благодаря чему отпадает необходимость в новых рукопожатиях TCP и используются средства повышения производительности TCP. Это соединение остаётся открытым не навсегда: праздные соединения закрываются по истечению некоторого времени (для задания минимального времени, на протяжении которого соединение должно оставаться открытым, сервер может использовать заголовок Keep-Alive (en-US)).

У постоянных соединений есть свои недочёты; даже работая вхолостую, они потребляют ресурсы сервера, а при высокой нагрузке могут проводиться DoS-атаки. В таких случаях большую эффективность могут обеспечить не постоянные соединения, которые закрываются как только освободятся.

Соединения HTTP/1.0 по умолчанию не являются постоянными. Для превращения их в постоянные надо присвоить заголовку Connection значение, отличное от close - обычно retry-after.

В HTTP/1.1 соединения являются постоянными по умолчанию, так что этот заголовок больше не требуется (но часто добавляется в качестве защитной меры на случай, если потребуется откат к HTTP/1.0).

Конвейерная обработка в HTTP (HTTP pipelining)

Примечание: Конвейерная обработка HTTP в современных браузерах не активирована по умолчанию:

  • Прокси с багами все ещё встречаются, что приводит к странным и непредсказуемым явлениям, которые веб-разработчикам трудно предсказать и диагностировать.
  • Конвейерную обработку сложно правильно реализовать: объем передаваемых ресурсов, используемая RTT и эффективная пропускная способность имеют непосредственное влияние на те улучшения, что обеспечиваются конвейерной обработкой. Конвейерная обработка HTTP, таким образом, даёт существенное улучшение не во всех случаях.
  • Конвейерная обработка подвержена проблеме HOL.

По этим причинам в HTTP/2 на смену конвейерной обработке пришёл новый алгоритм, мультиплексность (multiplexing).

По умолчанию запросы HTTP идут последовательно. Новый запрос выдаётся только после того, как получен ответ на предыдущий. Из-за запаздываний в сети и ограничений на пропускную способность это может приводить к тому, что сервер увидит следующий запрос с существенной задержкой.

Конвейерная обработка это процесс отсылки последовательных запросов по одному постоянному соединению не дожидаясь ответа. Таким образом избегают задержки соединения. Теоретически, производительность можно было бы повысить также за счёт упаковки двух запросов HTTP в одно и то же сообщение TCP. Типичный MSS (Maximum Segment Size - Максимальный размер сегмента) достаточно велик, чтобы вместить несколько простых запросов, хотя требования на объем запросов HTTP продолжают расти.

Не все типы запросов HTTP позволяют конвейерную обработку: только идемпотентные методы, а именно GET, HEAD, PUT и DELETE, можно перезапускать безопасно: в случае сбоя содержимое конвейерной передачи можно просто повторить.

В наши дни любой удовлетворяющий требованиям HTTP/1.1 прокси или сервер должен поддерживать конвейерную обработку, хотя на практике возникает множество ограничений, поэтому ни один из современных браузеров не активирует этот режим по умолчанию.

Доменное разделение (Domain sharding)

Примечание: Не используйте этот устаревший метод без крайней необходимости; вместо этого переходите на HTTP/2. В HTTP/2 доменное разделение больше не требуется: соединение HTTP/2 соединение прекрасно работает с параллельными неприоритезированными запросами. Доменное разделение даже вредит производительности. Большинство реализаций HTTP/2 использует метод, называемый слиянием соединений (connection coalescing) для возврата конечного доменного разделения.

Поскольку соединение HTTP/1.x является последовательными запросами, даже без упорядочивания, оно не может быть оптимальным без наличия достаточно большой пропускной способности. Браузеры находят решение в открытии нескольких соединений к каждому домену с отсылкой параллельных запросов. По умолчанию это когда-то было 2-3 соединения, но сейчас их число возросло примерно до 6 параллельных соединений. При попытке использовать большее количество есть риск спровоцировать защиту от DoS со стороны сервера.

Если сервер хочет иметь более быстрый ответ от веб-сайта или приложения, он может открыть больше соединений. Например, вместо того, чтобы иметь все ресурсы на одном домене, скажем, www.example.com, он может распределить их по нескольким доменам, www1.example.com, www2.example.com, www3.example.com. Каждый из этих доменов разрешается на том же сервере, и веб-браузер откроет 6 соединений к каждому (в нашем примере число соединений возрастёт до 18). Этот метод называют доменным разделением (domain sharding).

Заключение

Улучшение управлением соединениями даёт существенное увеличение производительности в HTTP. В HTTP/1.1 и HTTP/1.0 использование постоянного соединения – по крайней мере пока оно не начинает работать вхолостую – приводит к лучшей производительности. Однако, проблемы с конвейерной обработкой привели к созданию более совершенных способов управления соединением, реализованными в HTTP/2.