В стремлении к быстрому сайту многие разработчики упускают один важный момент: клиентскую (фронтендную) точку отказа (frontend SPOF – single point of failure). Причем, почти все инструменты тестирования скорости загрузки сайта также не выявят потенциальных проблем.
Возможность клиентской SPOF определяется особенностями рендеринга страниц браузерами. Для лучшего понимания механизма рендеринга рекомендую почитать мою предыдущую статью о критическом пути рендеринга страниц: habrahabr.ru/post/262239.
Типичный пример клиентской SPOF:
Главное, что мы знаем о критическом пути рендеринга: браузер блокируется на JS-коде, который он встречает на странице и на CSS-файлах (подробности пока опустим). Это значит, что мы не можем увидеть страницу (всю или её часть) до получения критических JS и CSS-ресурсов. Если эти ресурсы находятся на том же сервере, что и сайт, то это дело времени: подождём, загрузим и выполним (или быстро получим 404).
А что, если мы грузим ресурсы с других серверов? В этом случае браузер сначала должен сделать DNS-запрос, подключиться к серверу, послать запрос и подождать ответ. И только потом обработать полученный ресурс и продолжить рендеринг страницы.
Вот здесь мы и подошли к пониманию клиентской SPOF. Если на вашем сайте есть критический JS или CSS-ресурс, загружаемый из внешнего источника (другой домен), вы получаете клиентскую точку отказа (SPOF). При этом внешним источником может выступать любой сервер: узел CDN, внешний сайт с JS-API, хостинг JS-библиотек и т. д. При медленном ответе внешнего сервера получаем гарантированное проявление отказа (медленный или очень медленный рендеринг страницы). Если внешний сервер вообще не отвечает на запросы, браузер будет ждать до окончания таймаута (может быть до десятков секунд).
Это может выглядеть так (обратите внимание на время над скриншотами).
Для пользователя проявление SPOF в худшем случает выглядит как «сайт не работает», в лучшем случае как «сайт очень медленный». При этом ваш хостинг работает отлично, атаки на сайт нет, а эффект как от хорошего DDoS'а.
Основополагающая статья о проблеме была написана Стивом 1 июня 2010 года, однако постоянно приходится видеть сайты, которые подключают JS-библиотеки c внешних хостингов (apis.google.com, code.jquery.com, userapi.com, facebook, twitter и т. д.) Опасность составляет подключение скриптов в верхней части HTML-кода в синхронном режиме (без атрибута «async»).
Хорошо, всё это страшно, но мы же грузим файлы с супер-надёжных, никогда не падающих распределённых CDN-хостингов! Они всегда отвечают и делают это быстро! Проблемы вроде и нет…
К сожалению есть, вот почему.
В результате мы получаем бомбу замедленного действия. Обычно всё отлично работает, но наступает момент, когда сайт вдруг «падает». Особенно весело, что проблема может быть плавающей или затрагивать только часть пользователей.
Что со всем этим делать? Во-первых, нужно выяснить наличие SPOF на сайте. Для этого собираем все внешние хосты, с которых идет загрузка JS и CSS-ресурсов (также можно выяснить источники подключаемых шрифтов).
Во-вторых, нужно проверить, что будет при сбое внешних хостов. Лучшим средством для этого я считаю Webpagetest.org с закладкой SPOF. Вы можете вписать в это поле все хосты, которые будут тихо дропать пакеты и ничего не отвечать. Выбираем интересующую точку тестирования, браузер и запускаем обычный тест.
На выходе получаем два теста: нормальный и SPOF. На просмотре скриншотов рендеринга страницы видим тяжесть последствий SPOF (как правило задерживается момент начала рендеринга). На основе этих данных уже можно принимать решение о переносе ресурсов или страховке от сбоев.
Для исключения или минимизации последствий от клиентской SPOF можно предпринять такие меры.
Вот и все рекомендации. Если у вас накопился собственный опыт борьбы с клиентскими SPOF, пишите в комментариях.
Суть клиентской SPOF
Возможность клиентской SPOF определяется особенностями рендеринга страниц браузерами. Для лучшего понимания механизма рендеринга рекомендую почитать мою предыдущую статью о критическом пути рендеринга страниц: habrahabr.ru/post/262239.
Типичный пример клиентской SPOF:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery UI Datepicker - Default functionality</title>
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<link rel="stylesheet" href="/resources/demos/style.css">
<script>
$(function() {
$( "#datepicker" ).datepicker();
});
</script>
</head>
<body>
<p>Date: <input type="text" id="datepicker"></p>
</body>
</html>
Главное, что мы знаем о критическом пути рендеринга: браузер блокируется на JS-коде, который он встречает на странице и на CSS-файлах (подробности пока опустим). Это значит, что мы не можем увидеть страницу (всю или её часть) до получения критических JS и CSS-ресурсов. Если эти ресурсы находятся на том же сервере, что и сайт, то это дело времени: подождём, загрузим и выполним (или быстро получим 404).
А что, если мы грузим ресурсы с других серверов? В этом случае браузер сначала должен сделать DNS-запрос, подключиться к серверу, послать запрос и подождать ответ. И только потом обработать полученный ресурс и продолжить рендеринг страницы.
Вот здесь мы и подошли к пониманию клиентской SPOF. Если на вашем сайте есть критический JS или CSS-ресурс, загружаемый из внешнего источника (другой домен), вы получаете клиентскую точку отказа (SPOF). При этом внешним источником может выступать любой сервер: узел CDN, внешний сайт с JS-API, хостинг JS-библиотек и т. д. При медленном ответе внешнего сервера получаем гарантированное проявление отказа (медленный или очень медленный рендеринг страницы). Если внешний сервер вообще не отвечает на запросы, браузер будет ждать до окончания таймаута (может быть до десятков секунд).
Это может выглядеть так (обратите внимание на время над скриншотами).
Для пользователя проявление SPOF в худшем случает выглядит как «сайт не работает», в лучшем случае как «сайт очень медленный». При этом ваш хостинг работает отлично, атаки на сайт нет, а эффект как от хорошего DDoS'а.
Почему это важно?
Основополагающая статья о проблеме была написана Стивом 1 июня 2010 года, однако постоянно приходится видеть сайты, которые подключают JS-библиотеки c внешних хостингов (apis.google.com, code.jquery.com, userapi.com, facebook, twitter и т. д.) Опасность составляет подключение скриптов в верхней части HTML-кода в синхронном режиме (без атрибута «async»).
Хорошо, всё это страшно, но мы же грузим файлы с супер-надёжных, никогда не падающих распределённых CDN-хостингов! Они всегда отвечают и делают это быстро! Проблемы вроде и нет…
К сожалению есть, вот почему.
- Даже самые надёжные хостинги падают (даже облачные).
- Точки раздачи CDN могут быть далеко от пользователя (многие не имеют точек в России).
- Сервисы раздачи статики и хостинги библиотек часто бесплатные и не имеют никаких гарантий работоспособности и скорости отклика.
- Хост-источник может быть заблокирован на уровне провайдера/страны (например, в Китае или у нас в России).
В результате мы получаем бомбу замедленного действия. Обычно всё отлично работает, но наступает момент, когда сайт вдруг «падает». Особенно весело, что проблема может быть плавающей или затрагивать только часть пользователей.
Проверка на наличие и тяжесть последствий от SPOF
Что со всем этим делать? Во-первых, нужно выяснить наличие SPOF на сайте. Для этого собираем все внешние хосты, с которых идет загрузка JS и CSS-ресурсов (также можно выяснить источники подключаемых шрифтов).
Во-вторых, нужно проверить, что будет при сбое внешних хостов. Лучшим средством для этого я считаю Webpagetest.org с закладкой SPOF. Вы можете вписать в это поле все хосты, которые будут тихо дропать пакеты и ничего не отвечать. Выбираем интересующую точку тестирования, браузер и запускаем обычный тест.
На выходе получаем два теста: нормальный и SPOF. На просмотре скриншотов рендеринга страницы видим тяжесть последствий SPOF (как правило задерживается момент начала рендеринга). На основе этих данных уже можно принимать решение о переносе ресурсов или страховке от сбоев.
Решение проблемы
Для исключения или минимизации последствий от клиентской SPOF можно предпринять такие меры.
- Перевести по возможности все JS-библиотеки в асинхронный режим (аттрибут async).
- Убрать все внешние синхронные JS-библиотеки вниз кода, до закрывающего body.
- Использовать асинхронные версии подключения внешних API.
- Стандартные JS-библиотеки перенести на хостинг сайта и грузить с него.
- Перенести шрифты и их CSS-код на хостинг сайта.
- Регулярно проверять сайт на наличие SPOF.
Вот и все рекомендации. Если у вас накопился собственный опыт борьбы с клиентскими SPOF, пишите в комментариях.