Асинхронные HTTP-запросы

Для большинства сайтов загрузка страницы затрагивает десятки внешних объектов, основное время загрузки тратится на различные HTTP-запросы картинок, JavaScript- файлов и файлов стилей. При работе над оптимизацией времени загрузки страницы в сложном AJAX-приложении было исследовано, насколько можно уменьшить задержку за счет внешних объектов. Особый интерес при этом был вызван конкретной реализацией HTTP-клиента в известных браузерах и параметрами распространенных интернет- соединений, а также к тому, как они влияют на загрузку страницы, содержащих большое количество маленьких объектов.

Можно отметить несколько интересных фактов.

  • В IE, Firefox и Safari по умолчанию выключена техника HTTP-конвейера (англ. HTTP pipelining). Opera является единственным браузером, где она включена. Отсутствие конвейера при обработке запросов означает, что после каждого ответа на запрос его соединение освобождается прежде, чем отправлять новый запрос. Не следует путать конвейерную обработку с Connection: keep-alive, когда браузер может использовать одно соединение с сервером, чтобы загружать через него достаточно большое количество ресурсов. В случае конвейера браузер может послать несколько GET-запросов в одном соединении, не дожидаясь ответа от сервера. Сервер в таком случае должен ответить на все запросы последовательно. Это влечет дополнительные задержки на прохождение запроса туда-обратно, что, в общем случае, примерно равно времени ping (отнесенном к разрешенному числу одновременных соединений). Если же на сервере нет элементов поддержки активных HTTP-соединений, то это повлечет еще одно трехступенчатое TCP «рукопожатие», которое, в лучшем случае, удваивает задержку.
  • По умолчанию, в IE (а с ним работают сейчас 50-70% пользователей) можно установить только два внешних соединения на один хост при запросе на сервер, поддерживающий HTTP/1.1, или всего 8 исходящих соединений. Использование 4 хостов вместо одного может обеспечить большее число одновременных соединений. IP-адрес в таком случае не играет роли: все хосты могут указывать на один адрес.
  • У большинства DSL- или выделенных Интернет-соединений несимметричная полоса пропускания, она варьируется от 1,5 Мб входящего/128 Кб исходящего до 6 Мб входящего / 512 Кб исходящего и т.д. Отношение входящего к исходящему каналу, в основном, находятся в пределах от 5:1 до 20:1. Это означает для ваших пользователей, что отправка запроса занимает столько же времени, как и принятие ответа, который в 5-20 раз больше самого запроса. Средний запрос занимает около 500 байтов, поэтому больше всего влияния ощущают объекты, которые меньше, чем, может быть, 2,5-10 Кб. Это означает, что доставка небольших объектов может существенно снизить скорость загрузки страницы в силу ограничения на исходящий канал, как это ни странно.

Моделируем параллельные запросы

На основе заявленных предпосылок можно смоделировать эффективную ширину канала для пользователей, учитывая некоторые сетевые особенности при загрузке объектов различных размеров. Предположим, что каждый HTTP-запрос занимает 500 байтов и что HTTP-ответ содержит дополнительно к размеру запрошенного объекта еще 500 байтов заголовков. Это наиболее простая модель, которая рассматривает только ограничения на канал и его асимметрию, но не учитывает задержки на открытие TCP-соединения при первом запросе для активного соединения, которые, однако, сходят на нет при большом количестве объектов, передаваемых за один раз.

Следует также отметить, что рассматривается наилучший случай, который не включает другие ограничения, например, «медленный старт» TCP, потерю пакетов и т.д. Полученные результаты достаточно интересны, чтобы предложить несколько путей для дальнейшего исследования, однако, не могут никоим образом рассматриваться как замена экспериментов, проведенных с помощью реальных браузеров.

Чтобы выявить эффект от активных соединений и введения нескольких хостов, давайте возьмем пользователя с интернет-соединением с 1,5 Мб входящим / 384 Кб исходящим каналом, находящегося на расстоянии 100 мс без потери пакетов. Это в очень грубом приближении соответствует среднему ADSL-соединению на другом краю России с серверами, расположенными в Москве. Ниже показана эффективная пропускная способность канала при загрузке страницы с множеством объектов определенного размера. Эффективная пропускная способность определялась как отношение общего числа полученных байтов ко времени их получения.

SpeedUpYourWebsite.v1.2_img_26

Рис. 26. Влияние HTTP-конвейера и постоянного соединения на скорость передачи данных. Источник: www.die.net

Предварительные выводы

Следует отметить следующее.

  • Для относительно небольших объектов (левая часть графика) можно сказать, судя по большому пустому месту над линиями, что пользователь очень слабо использует свой канал, при этом браузер запрашивает объекты так быстро, насколько может. Для такого пользователя эффективное использование входящего канала наступает при загрузке объектах размером 100 Кб и более.
  • Для объектов размером примерно в 8 Кб можно удвоить эффективную пропускную способность канала, включив постоянные соединения на сервере и распределив запросы по 4 серверам. Это значительное преимущество.
  • Если пользователь включит конвейерную передачу запросов в своем браузере (для Firefox это будет network.http.pipelining в about:config), число используемых хостов перестанет играть значительную роль, и он будет задействовать свой канал еще более эффективно, однако, мы не сможем это контролировать на стороне сервера.

Возможно, более прозрачным будет следующий график, на котором изображено несколько различных интернет-соединений и выведено относительное ускорение для запроса страницы с множеством мелких объектов для случая использования 4 хостов и включения активного соединения на сервере. Ускорение измеряется относительно случая 1 хоста с выключенным keep-alive (0%).

SpeedUpYourWebsite.v1.2_img_27

Рис. 27. Выигрыш при включении постоянного соединения и нескольких хостов для различных пользователей. Источник: www.die.net

Что тут интересного?

  • Если вы загружаете много мелких объектов, меньших, чем 10 Кб, оба пользователя, и тот, кто находится локально, и тот, кто на другом конце континента, почувствуют значительное ускорение от включения активного соединения и введения 4 хостов вместо одного.
  • Чем дальше находится пользователь, тем значительнее выигрыш.
  • Чем больше скорость соединения, тем больше выигрыш. Пользователь с ethernet- каналом в 100 Мб на расстоянии всего 20 мс от сервера почувствует наибольшее ускорение.

Влияние заголовков

Давайте теперь посмотрим, как размер заголовков влияет на эффективную пропускную способность канала. Предыдущий график предполагает, что размер заголовков составляет 500 байтов дополнительно к размеру объекта, как для запроса, так и для ответа. Как же изменение этого параметра отразится на производительности нашего 1,5 Мб / 384 Кб канала и расстояния до пользователя в 100 мс? Предполагается, что пользователь уже изначально использует 4 хоста и активное соединение.

SpeedUpYourWebsite.v1.2_img_28

Рис. 28. Влияние заголовков на эффективную пропускную способность канала. Источник: www.die.net

На графике хорошо видно, что при небольших размерах файлов основные задержки приходятся на исходящий канал. Браузер, отправляющий «тяжелые» запросы на сервер (например, с большим количеством cookie), по-видимому, замедляет скорость передачи данных более чем на 40% для этого пользователя. Естественно, размер cookie можно и нужно регулировать на сервере. Отсюда простой вывод: cookie нужно, по возможности, делать минимальными или направлять ресурсные запросы на серверы, которые не выставляют cookie.

Все полученные графики являются результатом моделирования и не учитывают некоторые реальные особенности окружающего мира. Но можно взять и проверить полученные результаты в реальных браузерах в «боевых» условиях и убедиться в их состоятельности. Реальное положение дел определенно усугубляет ситуацию, ибо медленные соединения и большие задержки становятся еще больше, а быстрые методы соединения по-прежнему выигрывают.

Posted in Разгони свой сайт.