RE:NODE

Веб-хостинг11 мин чтения

TTFB и Core Web Vitals: что на самом деле меняет хостинг

Какую часть LCP, INP и CLS контролирует ваш сервер, как правильно измерить время до первого байта и какие исправления стоят денег, а не усилий.

0 прочтений

Хостингу принадлежит одна цифра в отчёте о производительности сайта: время до первого байта, TTFB. Это ожидание между тем, как браузер запросил страницу, и тем, как пришёл первый байт ответа; оно складывается из DNS, установки соединения, расстояния между посетителем и машиной и времени, которое ваш сервер тратит на размышления. Всё, что идёт после первого байта - размер картинок, объём исполняемого JavaScript, прыгает ли вёрстка, - забота вашего сайта, и никакой купленный тариф этого не изменит.

Кажется, что доля небольшая, но это не так. TTFB - пол под Largest Contentful Paint: если сервер отвечает 1,5 секунды, даже идеальный фронтенд провалит порог в 2,5 секунды. Возьмите TTFB под контроль, и остальное станет решаемым. Игнорируйте его, и ничего из остального не хватит.

Три Core Web Vitals и где среди них TTFB#

Core Web Vitals - набор из трёх полевых метрик, которые измеряются на реальных визитах и сообщаются по 75-му процентилю за скользящие 28 дней. Пороги:

МетрикаЧто измеряетХорошоПлохо
LCPВремя до отрисовки самого крупного элемента2,5 с или меньшебольше 4,0 с
INPОтзывчивость на касания, клики и клавиши200 мс или меньшебольше 500 мс
CLSНасколько смещается вёрстка при загрузке0,1 или меньшебольше 0,25

INP заменил First Input Delay в качестве Core Web Vital в марте 2024 года, и он строже: он смотрит на худшее взаимодействие на странице, а не только на первое, и измеряет время до отрисовки следующего кадра, а не только до начала работы обработчика.

TTFB не входит в эти три. Это диагностическая метрика, и рекомендация такова: 0,8 секунды или меньше для хорошей оценки, а всё, что больше 1,8 секунды, считается плохим. Он важен потому, что LCP раскладывается на четыре части, идущие по порядку: TTFB, задержка до того, как браузер обнаружит ресурс LCP, время загрузки этого ресурса и задержка до отрисовки. Первая целиком на стороне сервера, и она прямо вычитается из бюджета остальных трёх.

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

Чего ждёт первый байт#

resolve, затем connectзапрос отправленответ началсяПоиск DNSтолько первый визитTCP и TLS2-3 кругаРабота сервераPHP, запросы, кэшПервый байтздесь кончается TTFB
Чего ждёт первый байт

Измеряйте каждую часть, а не гадайте. curl печатает всю разбивку:

bash
$ curl -s -o /dev/null -w "dns: %{time_namelookup}s  connect: %{time_connect}s \tls: %{time_appconnect}s  ttfb: %{time_starttransfer}s  total: %{time_total}s\n" \  https://example.com/

Это накопленное время от начала запроса, так что стоимость каждого этапа - разница с предыдущим. Типичный здоровый результат с машины на том же континенте выглядит так: DNS меньше 30 мс, connect добавляет 20-40 мс, TLS - ещё 20-40 мс, а первый байт приходит через 30-150 мс после этого в зависимости от того, что пришлось делать серверу.

Измерение искажают две вещи. Запустите его дважды: второй запуск использует уже полученный ответ DNS и точнее показывает вернувшегося посетителя. И запускайте не из офиса, потому что ваша собственная задержка до сервера - не задержка ваших посетителей.

Для серверной части инструмент, превращающий догадку в число, - Server-Timing. Его выдаёт ваше приложение, а инструменты разработчика в браузере показывают:

code
Server-Timing: db;dur=53, render;dur=31, cache;desc="MISS"

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

Что на самом деле меняет хостинг#

Четыре вещи, в порядке того, насколько они обычно важны.

Работа сервера. Время между получением запроса сервером и началом ответа. Для сайта на PHP это запуск PHP, загрузка фреймворка, запросы к базе и рендер шаблона. Именно здесь быстрый тариф действительно быстрее: больше доли CPU - меньше очередей, больше памяти - кэши остаются тёплыми. Здесь же и самые большие бесплатные выигрыши: OPcache, кэш объектов и исправление страницы, выполняющей 400 запросов.

Расстояние. Свет в оптоволокне проходит примерно 200 км за миллисекунду, а каждому запросу до первого байта нужно несколько круговых обменов. С сервера в Германии примерное время кругового обмена такое:

Из Германии доПримерный RTT
Западной Европы10-30 мс
Восточной Европы, Турции30-70 мс
Восточного побережья США85-110 мс
Западного побережья США, Индии130-180 мс
Бразилии180-220 мс
Австралии250-300 мс

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

Установка соединения. HTTP/2 позволяет многим запросам делить одно соединение, так что рукопожатие оплачивается один раз, а не на каждый ресурс. TLS 1.3 завершается за один круг там, где 1.2 требовал двух. Keep-alive важен по той же причине. Это в основном значения по умолчанию вашего веб-сервера, и обычно они уже правильные.

Диск и память. Хранилище NVMe сокращает всё, что обращается к файловой системе: холодное чтение файла PHP, страницу базы данных, которой нет в памяти, большую загрузку. Заметнее всего это на базе данных, не помещающейся в RAM. Цифры - в статье что на самом деле меняет NVMe.

На RE:NODE всё это стоит на NVMe в пуле ZFS в Германии, а доля CPU в вашем тарифе - жёсткое ограничение, а не разрешение на всплески. Жёсткий лимит менее лестен в бенчмарке и намного предсказуемее в продакшене: сервер на 100% работает медленно, но его никогда не приостанавливают, а графики консоли показывают память, CPU и диск относительно лимитов, так что видно, в какой из них вы на самом деле упираетесь. Почему такое ограничение - честная модель, объясняет статья общий CPU и шумные соседи.

Чего хостинг изменить не может#

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

  • Вес изображений. Hero-картинка в 3 МБ - это 3 МБ с любого сервера. Элемент LCP на большинстве страниц - изображение, и решение - экспортировать его в размере отображения в WebP или AVIF.
  • Исполнение JavaScript. INP решается на устройстве посетителя вашим основным потоком. Более быстрый сервер не сделает задачу в 400 мс короче.
  • Смещение вёрстки. CLS вызывают изображения без размеров, реклама и встраиваемое содержимое, которое вставляется само, и шрифты, подменяющиеся на другой размер. Всегда чистый фронтенд.
  • Сторонние теги. Аналитика, чат-виджеты, менеджеры согласия и пиксели загружаются с чужих серверов по чужому расписанию.
  • Блокирующие отрисовку ресурсы. Таблица стилей в head блокирует отрисовку, пока не придёт, кто бы её ни хостил.
  • Устройство и сеть посетителя. Пятилетний телефон в поезде - это и есть 75-й процентиль.

Практическая проверка перед повышением тарифа: посмотрите графики CPU и памяти в самый загруженный час. Если у вас 20% CPU и половина памяти, более крупный тариф ничего не изменит, а время до первого байта, которым вы недовольны, идёт от вашего кода, ваших запросов или расстояния. Тот же довод, но подробнее, - в статье когда пора переходить на другой тариф.

Как измерять правильно: поле и лаборатория#

Два вида данных, и они отвечают на разные вопросы.

Полевые данные приходят от реальных визитов. Публичный набор данных Chrome лежит в основе отчёта Core Web Vitals в Search Console и верхней половины PageSpeed Insights, агрегированный за 28 дней по 75-му процентилю. Именно им пользуется поиск, он охватывает вашу реальную аудиторию и устройства, и он медленно меняется: сегодняшнее исправление проявится в следующие недели.

Лабораторные данные приходят из синтетического прогона: Lighthouse, нижняя половина PageSpeed Insights, WebPageTest. Они воспроизводимы и мгновенны, что делает их подходящими для сравнения двух версий страницы, и они не могут нормально измерить INP, потому что никто не взаимодействует. Лабораторный прогон к тому же использует имитированное соединение, так что его LCP - не LCP ваших посетителей.

Если у сайта слишком мало трафика для полевых данных, собирайте свои собственные библиотекой web-vitals, которая отправляет те же метрики из реальных сессий на любой endpoint. Сто реальных визитов скажут больше, чем тысяча лабораторных прогонов.

Когда вы ищете именно серверную проблему, самый быстрый цикл - curl снаружи, в цикле, в тихий час и в загруженный. TTFB, который в порядке в 3 ночи и ужасен в 9 вечера, - проблема ёмкости. Постоянно плохой - проблема кода или запросов. Плохой только у некоторых страниц - отсутствующий индекс или медленный сторонний вызов на пути запроса.

Исправляем TTFB по порядку#

  1. Кэшируйте HTML. Страница, отданная из кэша, обходит фреймворк, базу данных и большую часть риска. Полностраничный кэш превращает динамический ответ в 600 мс в 20 мс. Для WordPress это плагин кэша страниц плюс кэш объектов; для фреймворка - кэш ответов или обратный прокси. Что отправлять вместе с ним, чтобы браузеры и CDN сотрудничали, описано в статье заголовки HTTP-кэширования простыми словами.
  2. Включите OPcache и не трогайте. PHP без OPcache перекомпилирует каждый файл на каждом запросе. С opcache.enable=1 и достаточным opcache.memory_consumption эта работа делается один раз. В продакшене opcache.validate_timestamps=0 убирает вызов stat на каждый файл ценой того, что при деплое нужен сброс. Остальное - в статье настройки php.ini, которые важны.
  3. Считайте запросы. Самая частая причина TTFB в 900 мс - цикл, выполняющий один запрос на строку. Логируйте число запросов на страницу при разработке; всё, что больше примерно 30 на обычную страницу, требует объяснения.
  4. Уберите блокирующий сторонний вызов. Обращение к внешнему API внутри рендера страницы делает ваш TTFB зависимым от чужой доступности. Вынесите его в очередь, закэшируйте результат или примите риск осознанно.
  5. Уберите цепочки редиректов. Каждый переход - полный круговой обмен, а редирект на другое имя хоста снова добавляет DNS и TLS. http://example.com на https://example.com на https://www.example.com - два избежимых ожидания при каждом первом визите.
  6. Сжимайте и держите соединения тёплыми. gzip или brotli для текста, HTTP/2 включён, keep-alive включён. Обычно это значения по умолчанию, но проверьте, а не предполагайте.
  7. И только потом покупайте больше сервера. Если CPU упирается под трафиком или память на лимите, проблема в тарифе, а всё выше - перестановка мебели. Как рассчитать, что нужно, до самого дня, описано в статье подбор размера веб-приложения для дня запуска.

Исправляем LCP, когда TTFB хорош#

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

  • Не откладывайте загрузку изображения LCP. loading="lazy" на hero-картинке задерживает именно то, что измеряется. Откладывайте только то, что ниже первого экрана.
  • Дайте ему приоритет. fetchpriority="high" на изображении LCP говорит браузеру загружать его раньше других картинок, а ссылка preload помогает, когда изображение обнаруживается поздно, например из CSS.
  • Заранее подключайтесь к неизбежным origin. rel="preconnect" к хосту шрифтов или изображений оплачивает DNS и TLS параллельно, а не последовательно.
  • Отдавайте шрифты со своего origin и с `font-display: swap`. Текст, невидимый, пока грузится шрифт, - это текст, который не отрисован.
  • Задавайте `width` и `height` каждому изображению. Это самое большое исправление CLS, и оно ничего не стоит.
  • Сократите блокирующий отрисовку CSS. Встройте то, что нужно первому экрану, и загружайте остальное асинхронно, если ваша сборка позволяет это без переписывания.

Статический сайт получает большую часть этого бесплатно, и это часть довода за то, чтобы строить такой, где контент позволяет, - см. хостинг статических сайтов. CMS получает это от слоя кэширования плюс дисциплины с плагинами; конкретная версия - скорость и кэширование WordPress.

FAQ#

Какой TTFB считается хорошим?

Менее 800 мс по 75-му процентилю - опубликованный порог хорошей оценки, но это потолок, а не цель. Кэшированная страница на близком сервере отвечает за 30-80 мс; динамическая страница, выполняющая настоящую работу, всё равно должна уложиться в 300 мс. Если вы за секундой, что-то не так, а не просто не оптимизировано.

Улучшит ли более дорогой тариф мои Core Web Vitals?

Только если вы ограничены ресурсами. Больше CPU и памяти сокращают часть TTFB, связанную с работой сервера, что помогает LCP. Для INP, CLS, веса изображений и сторонних скриптов они бесполезны, а именно оттуда берётся большинство проваленных оценок. Прежде чем тратить деньги, посмотрите графики использования.

Исправляет ли CDN TTFB?

Для кэшированных ответов - да, разительно, потому что ответ приходит с машины рядом с посетителем. Для всего, что CDN кэшировать не может - страница с входом, оформление заказа, вызов API, - запрос по-прежнему идёт до вашего origin и обратно, так что цифру по-прежнему определяют скорость origin и расстояние до него.

Является ли TTFB фактором ранжирования?

Не напрямую. LCP, INP и CLS входят в сигналы качества страницы, а TTFB входит в LCP. Относитесь к нему как к средству, а не к цели: причина исправлять его в том, что посетители уходят с медленных страниц, а этот эффект больше любой поправки в ранжировании.

Почему в Lighthouse у меня 100, а отчёт Search Console провален?

Потому что они измеряют разное. Lighthouse - один синтетический прогон на имитированном соединении из дата-центра. Search Console сообщает, что видели реальные посетители на реальных устройствах и в реальных сетях за последние 28 дней по 75-му процентилю. Доверяйте полевым данным, а лабораторный прогон используйте для сравнения изменений.

Через какое время после исправления отчёт улучшится?

Полевые данные - скользящее окно в 28 дней, поэтому изменению нужно несколько дней, чтобы показать движение, и около месяца, чтобы отразиться полностью. Проверяйте лабораторными инструментами и собственными измерениями на реальных пользователях сразу; официальный отчёт воспринимайте как подтверждение, а не как обратную связь.


Комментарии

Полностью анонимно: без аккаунта, без почты, без cookie. Мы храним имя, которое вы ввели, текст и время - больше ничего. Количество ссылок ограничено, разметка не отображается.

0/2000