Азат Ш.

Нейтрализуем издержки сетей

Нейтрализуем издержки сетей

5 октября 2022 г.

6 минут на прочтение

Также переведено на:

Скорость загрузки сайта влияет на ранжирование в поисковой выдаче и восприятие пользователем, а, следовательно, на конверсию.

Средняя скорость реакции человека 200-250 миллисекунд.

То, что происходит в течение 250 миллисекунд человек воспринимает как «мгновенно», а несколько сотен миллисекунд - как «достаточно быстро».

Загрузку веб-страницы можно условно разделить на три большие части:

  1. Сеть
  2. Сервер
  3. Клиент

В этой статье рассматривается первая часть, но и другие две будут отчасти затронуты.

Как работает браузер?

Сначала пользователь вбивает URL в адресную строку браузера. Для примера возьмём адрес этой статьи: https://azat.io/ru/fluid-interfaces.

Браузер разбивает адрес на части:

  • https - протокол
  • azat.io - хост
  • /ru/fluid-interfaces - ресурс

На основе хоста браузер получает IP-адрес сервера, где находится сайт. Для этого используется DNS.

DNS-сервера сравнивают жёлтым телефонным книжкам с номерами телефонов, где имени контакта соответствует хост сайта, а номеру — его IP-адрес в сети.

Если запрос к хосту уже выполнялся, то запроса к DNS повторно не будет, и IP-адрес сервера браузер возьмёт из локального кэша.

Также браузер посещает файл hosts, который содержит базу доменных имен и используется для их трансляции в сетевые адреса узлов (в macOS, например, этот файл находится в /private/etc/hosts). Но это уже детали.

По IP-адресу посредством протокола передачи данных TCP устанавливается соединение. Для TCP-соединения важен порт: для протокола HTTP — 80, для HTTPS — 443.

При установке соединения по протоколу HTTPS происходит рукопожатие —TLS Handshake:

Клиент отправляет серверу сообщение, которое содержит версию криптографического протокола TLS и список поддерживаемых алгоритмов шифрования и методов компрессии данных. Сервер отвечает клиенту тем же и посылает SSL сертификат сервиса, который содержит публичный ключ.

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

После этого данные, полученные посредством HTTP, будут передаваться в зашифрованном виде с помощью симметричного ключа.

После установки соединения формируется HTTP-заголовок.

HTTP-заголовок — это текстовый заголовок, который начинается со строки, где указывается метод (GET, POST, PUT и т.д.), за которой следует локейшен ресурса и версия HTTP протокола. Кроме того, указывается заголовок Host, который обычно совпадает с доменным именем и заголовок Connection: close. Последний добавляется, потому что некоторые браузеры поддерживают постоянные соединения.

GET / HTTP/1.1
Host: azat.io
Connection: close
[...]

Ответ на HTTP-запрос содержит информацию об ошибке и её коде или заголовок со статус-кодом 200 и HTML-страницей. Время от начала процесса до получения первого пакета данных HTML называется Time to First Byte — TTFB.

Далее браузер начинает процесс парсинга HTML-страницы, браузер формирует DOM и CSSOM, создаёт дерево рендеринга и набор элементов, на основе которых делается отображение.

Скрипты могут изменять положение и размер элементов, что запускает процессы reflow и redraw. Парсинг страницы — задача объёмная, которая включает как минимум один reflow и один redraw.

Устройство сетевого взаимодействия

Ширина канала — максимальный объём данных, который можно передать через соединение за определённый период времени. Она измеряется в мегабитах в секунду и сильно влияет на скорость загрузки веб-страницы. Ширину канала можно сравнить с водопроводной трубой: чем она шире, тем больше воды сможет по ней пройти за единицу времени.

На мобильных устройствах ширина канала ниже, особенно в сетях 3G. Поэтому здесь влияние сети на скорость загрузки страницы выше, чем на десктопе.

Время, которое нужно, чтоб запрос дошёл от клиента до сервера и обратно называется время приёма-передачи или Round trip time — RTT.

Время приёма-передачи можно узнать с помощью команды ping. Среднее время идеального раунд трипа - 50 миллисекунд.

PING azat.io (75.2.60.5): 56 data bytes
64 bytes from 75.2.60.5: icmp_seq=0 ttl=117 time=31.788 ms
64 bytes from 75.2.60.5: icmp_seq=1 ttl=117 time=32.157 ms
64 bytes from 75.2.60.5: icmp_seq=2 ttl=117 time=31.282 ms
64 bytes from 75.2.60.5: icmp_seq=3 ttl=117 time=31.204 ms

--- azat.io ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 31.204/31.608/32.157/0.388 ms

Кроме HTML веб-страница состоит также из CSS, JS файлов, картинок и т. п. На каждый ресурс нужен поход по сети.

На RTT напрямую влияет задержка — latency. Задержка растёт по мере роста расстояния до конечного сервера и маршрута к нему, поскольку данные передаются не через одну сеть, а проходят через несколько автономных систем. Также влияет качество сети: сети 3G могут иметь задержку 100-500 миллисекунд, что сильно замедляет загрузку контента. Другие причины: серверы, которые не могут справиться с большим объёмом трафика, загрузка сетей в местах скопления людей, и неэффективная работа маршрутизаторов.

С улучшением технологий ширина канала увеличивается, но задержку как минимум ограничивает скорость света.

Расстояние между Марсом и Землёй в разное время составляет от 55.75 млн. км до 401 млн. км. Так, сообщение с Марса будет доходить от 3 минут и 22 секунд до 44 минут.

По этой причине в Австралии и Новой Зеландии интернет-ресурсы грузятся, как правило, медленнее, поскольку большая часть серверов размещается в США и Европе.

В нестабильных сетях возникают проблемы с потерей пакетов, что приводит к росту RTT.

Как измерить скорость загрузки страницы?

Чтобы оценить перфоманс, можно использовать Lighthouse в инструментах разработчика Chrome DevTools или аналогичный облачный сервис.

Что там можно увидеть:

First Contentful Paint — время, которое требуется браузеру для отображения первой части содержимого DOM. Быстрым считается FCP, который не превышает 1.8 секунды.

Speed Index — скорость визуального отображения контента при загрузке страницы. Браузер оценивает эту скорость, сравнивая сайт с другими из HTTP-архива.

Largest Contentful Paint — время загрузки самого большого элемента в области просмотра пользователя.

Time to Interactive — время с момента начала загрузки до момента, когда страница станет полностью интерактивной.

Total Blocking Time — время блокировки страницы, когда пользователю недоступны никакие действия.

Cumulative Layout Shift — смещение макета из-за асинхронной загрузки ресурсов.

Что можно с этим сделать?

Спецификация медленного старта TCP устанавливает, что объём первого пакета данных всегда составляет 14 кБ.

Cервер не знает, с каким объёмом данных справится интернет-соединение, поэтому отправляется небольшое надёжное количество данных — 10 TCP пакетов с максимальным размером 1500 байтов.

По этой причине веб-страница размером в 14 кБ грузится существенно быстрее, чем веб-страница размером 15 кБ из-за дополнительного RTT, хотя разница между ними минимальна.

Для уменьшения объёма данных следует использовать алгоритмы сжатия данных, такие как Brotli и Gzip.

Принцип работы CDN

При использовании TCP/IP на задержки влияет количество маршрутов между клиентом и сервером, чем дальше пользователь находится от сервера, тем дольше он ждёт ответа. Проблему задержек решают сервисы доставки содержимого — CDN. Это распределенные по миру серверы, которые хранят статические данные.

Чтобы уменьшить влияние задержек нужно избегать цепочек последовательных вызовов. Например, когда шрифт подгружаются из CSS файлов.

Неплохой вариант — использование preload:

html
<link
  rel="preload"
  href="/fonts/awesome-font.woff2"
  type="font/woff2"
  as="font"
  crossorigin
/>

Во время загрузки стороннего веб-шрифта текст должен оставаться видимым. Это можно сделать, включив font-display: swap:

css
@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 400;
  src: url('/fonts/awesome-font.woff2') format('woff2');
  font-display: swap;
}

Отображение страницы замедляют редиректы для показа первой страницы. Вместо редиректа на мобильную версию сайта лучше верстать адаптивно.

Для ускорения показа страницы используют технику инлайна стилей, поскольку они загружаются с первого запроса, а даже preload только со второго.

При работе со скриптами нужно использовать атрибуты defer/async, чтобы не было блокировок при отрисовке страницы. Также важно хорошо продумывать код-сплиттинг для оптимизации скорости загрузки.

Ленивая загрузка изображений и свойство content-visibility в CSS - это хорошие способы уменьшения времени рендеринга страниц с большим количеством контента.

Использование протокола HTTP/2 ускоряет загрузку страницы. Это достигается благодаря тому, что при использовании второй версии протокола несколько запросов могут быть отправлены через одно TCP-соединение, независимо от типа ресурса, а также благодаря сжатию HTTP-заголовков.

Отредактировать эту страницу

Предыдущая статья

Резиновые интерфейсы