Управление соединениями в HTTP 1.x
Управление соединениями в HTTP/1.x
Управление соединениями — важная тема в HTTP: открытие и поддержание соединений во многом влияет на производительность веб-сайтов и веб-приложений. В HTTP/1.x существует несколько моделей: кратковременные соединения, постоянные соединения и конвейеризация HTTP.
В качестве транспортного протокола HTTP в основном использует TCP, обеспечивающий соединение между клиентом и сервером. На заре своего развития HTTP использовал единственную модель обработки таких соединений. Эти соединения были кратковременными: новое соединение создавалось при каждой отправке запроса и закрывалось после получения ответа.
Эта модель имела существенное ограничение производительности: открытие каждого TCP-соединения требует значительных ресурсов. Между клиентом и сервером необходимо обменяться несколькими сообщениями. Сетевая задержка и пропускная способность влияют на производительность при отправке запроса. Для предоставления всего необходимого объёма информации современным веб-страницам требуется множество запросов (дюжина или больше), что делает эту раннюю модель неэффективной.
В HTTP/1.1 появились две новые модели. Модель постоянного соединения сохраняет соединения открытыми между последовательными запросами, сокращая время, необходимое для открытия новых соединений. Модель конвейеризации HTTP идёт ещё дальше: она позволяет отправлять несколько последовательных запросов, не дожидаясь ответа, что значительно уменьшает сетевую задержку.
Примечание: В HTTP/2 добавлены дополнительные модели управления соединениями.
Важно отметить, что управление соединениями в HTTP относится к соединению между двумя соседними узлами, то есть действует от узла к узлу, а не от конца до конца. Модель соединения между клиентом и первым прокси может отличаться от модели соединения между прокси и целевым сервером (или любыми промежуточными прокси). Заголовки HTTP, участвующие в определении модели соединения, такие как Connection и Keep-Alive, относятся к заголовкам, действующим от узла к узлу, и их значения могут изменяться промежуточными узлами.
С этой темой связано понятие обновления соединения HTTP: соединение HTTP/1.1 обновляется до другого протокола, например TLS/1.0, WebSocket или даже HTTP/2 без шифрования. Этот механизм обновления протокола подробнее описан в другом разделе.
Кратковременные соединения
Исходная модель HTTP, а также модель, используемая по умолчанию в HTTP/1.0, — это кратковременные соединения. Каждый запрос HTTP выполняется в отдельном соединении; это означает, что перед каждым запросом HTTP выполняется TCP-рукопожатие, а сами запросы отправляются последовательно.
Само TCP-рукопожатие требует времени, но TCP-соединение адаптируется к нагрузке и становится эффективнее при длительном использовании (то есть при «прогретом» соединении). Кратковременные соединения не используют эту особенность TCP, поэтому производительность оказывается ниже оптимальной: данные приходится снова и снова передавать по новым, «холодным» соединениям.
Эта модель используется по умолчанию в HTTP/1.0 (если заголовок Connection отсутствует или его значение задано как close). В HTTP/1.1 эта модель используется только в том случае, если заголовок Connection передан со значением close.
Примечание: Если только вы не работаете с очень старой системой, не поддерживающей постоянные соединения, нет веских причин использовать эту модель.
Постоянные соединения
У кратковременных соединений есть два существенных недостатка: для установления нового соединения требуется значительное время, а производительность базового TCP-соединения повышается, только когда оно используется в течение некоторого времени (то есть становится «прогретым»). Чтобы уменьшить влияние этих проблем, ещё до появления HTTP/1.1 была разработана концепция постоянного соединения. Его также называют keep-alive-соединением.
Постоянное соединение остаётся открытым в течение некоторого времени и может повторно использоваться для нескольких запросов, избавляя от необходимости выполнять новое TCP-рукопожатие и позволяя использовать возможности TCP для повышения производительности. Такое соединение не остаётся открытым бесконечно: соединения, простаивающие бездействуя, закрываются спустя некоторое время (сервер может использовать заголовок Keep-Alive, чтобы указать минимальное время, в течение которого соединение должно оставаться открытым).
У постоянных соединений есть и недостатки: даже в состоянии простоя они потребляют ресурсы сервера, а при высокой нагрузке могут проводиться DoS-атаки. В таких случаях лучшую производительность могут обеспечить непостоянные соединения, которые закрываются сразу после перехода в состояние простоя.
По умолчанию соединения HTTP/1.0 не являются постоянными. Если установить для заголовка Connection любое значение, кроме close, обычно retry-after, соединение станет постоянным.
В HTTP/1.1 постоянные соединения используются по умолчанию, поэтому этот заголовок больше не нужен (но его часто добавляют для защиты на случай необходимости перейти на HTTP/1.0).
Конвейеризация HTTP
Примечание: В современных браузерах конвейеризация HTTP по умолчанию не включена:
- Ошибочно работающие прокси по-прежнему встречаются часто и приводят к странному и непредсказуемому поведению, которое веб-разработчикам трудно предвидеть и диагностировать.
- Правильно реализовать конвейеризацию сложно: на выигрыш от конвейера напрямую влияют размер передаваемого ресурса, фактическое значение RTT и пропускная способность. Если эти параметры неизвестны, важные сообщения могут задерживаться за неважными. Более того, представление о важности меняется по мере построения страницы! Поэтому в большинстве случаев конвейеризация HTTP даёт лишь незначительное улучшение.
- Конвейеризация подвержена проблеме блокировки начала очереди.
По этим причинам конвейеризацию вытеснил более совершенный алгоритм — мультиплексирование, используемое в HTTP/2.
По умолчанию запросы HTTP отправляются последовательно. Следующий запрос отправляется только после получения ответа на текущий. Из-за сетевых задержек и ограничений пропускной способности сервер может получить следующий запрос с существенной задержкой.
Конвейеризация — это отправка последовательных запросов по одному и тому же постоянному соединению без ожидания ответа. Это позволяет избежать задержек, связанных с соединением. Теоретически производительность можно также повысить, если упаковать два запроса HTTP в одно TCP-сообщение. Типичное значение MSS (максимальный размер сегмента) достаточно велико, чтобы вместить несколько простых запросов, хотя размер запросов HTTP продолжает расти.
Конвейеризацию можно применять не ко всем типам запросов HTTP: безопасно повторно отправлять можно только идемпотентные методы: GET, HEAD, OPTIONS, TRACE, PUT и DELETE. Если произойдёт сбой, содержимое конвейера можно отправить повторно.
Сегодня все прокси и серверы, соответствующие HTTP/1.1, должны поддерживать конвейеризацию, хотя на практике у многих есть ограничения. Это одна из важных причин, по которым ни один современный браузер не включает эту возможность по умолчанию.
Шардирование доменов
Примечание: Если у вас нет особой неотложной необходимости, не используйте этот устаревший приём; вместо него перейдите на HTTP/2. В HTTP/2 шардирование доменов больше не нужно: соединение HTTP/2 хорошо справляется с параллельными запросами без заданного приоритета. Шардирование доменов даже снижает производительность. В большинстве реализаций HTTP/2 используется метод, называемый объединением соединений, который отменяет возможное шардирование доменов.
Поскольку соединение HTTP/1.x передаёт запросы последовательно, даже если их порядок не задан, оно не может работать оптимально без достаточной пропускной способности. В качестве решения браузеры открывают несколько соединений с каждым доменом и отправляют параллельные запросы. Раньше по умолчанию использовалось от 2 до 3 соединений, но сейчас чаще открывают 6 параллельных соединений. Попытка открыть больше соединений может привести к срабатыванию защиты от DoS-атак на стороне сервера.
Если серверу нужно ускорить ответ веб-сайта или приложения, он может принудительно открыть больше соединений. Например, вместо размещения всех ресурсов в одном домене, скажем www.example.com, их можно распределить по нескольким доменам: www1.example.com, www2.example.com, www3.example.com. Каждый из этих доменов указывает на тот же сервер, и веб-браузер откроет по 6 соединений с каждым из них (в нашем примере общее число соединений увеличится до 18). Этот приём называется шардированием доменов.
Заключение
Улучшенное управление соединениями позволяет значительно повысить производительность HTTP. При использовании HTTP/1.1 или HTTP/1.0 наилучшую производительность обеспечивает постоянное соединение, по крайней мере до тех пор, пока оно не перейдёт в состояние простоя. Однако неудача конвейеризации привела к разработке более совершенных моделей управления соединениями, которые были включены в HTTP/2.
См. также
© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Connection_management_in_HTTP_1.x