Кейс Guardian: свежие новости за 1 секунду

Guardian – одна из крупнейших газет в Великобритании, а сайт издания является одним из самых популярных онлайн-СМИ в этой стране. Трафик на сайт превышает 100 миллионов посетителей в месяц. Издание получает значительные доходы от рекламы, которая показывается посетителям сайта. Иметь максимально комфортный сайт для посещения – одна из ключевых задач команды Guardian.

Патрик Хаманн, старший разработчик Guardian, рассказывает, как его команде удалось ускорить сайт Guardian.

Постановка задачи

Команда начала с опроса пользователей относительно того, что для них важно. Для опроса были определены 17 ключевых потенциальных показателей сайта. Были опрошены 3000 пользователей сайта. Скорость загрузки сайта оказалась №2 по важности, «проиграв» только такому фактору как «легко найти нужный контент».

Эти данные подтверждают другие исследования, например, опубликованное на Web Performance Today исследование о том, что ожидания пользователей относительно скорости загрузки сайтов постоянно растут – пользователи ждут все более и более быстрой загрузки сайта.

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

  • 0-100 мс: задержка не воспринимается.
  • 100-300 мс: задержка заметна пользователю.
  • 300-1000 мс: воспринимается как задержка, которая не противоречит нормальному функционированию.
  • 1000-10 000 мс: пользователь переключается на выполнение других задач, ожидая, пока выполнится это действие.

  • 10 000 мс: пользователь оставляет попытки выполнить задачу.

(цитируется по книге Ильи Григорика «Высокопроизводительная работа браузера в сети»)

Поэтому команда Хаманна поставила себе цель – отображать содержимое статьи с сайта за 1 секунду (1000 мс). Для этой цели они приняли методику назначения «бюджета» в миллисекундах различным задачам, которые выполняются, чтобы браузер мог показать основное содержимое статьи.

В итоге команда установила 4 ключевых правила для работы над проектом:

  • Основной контент статьи должен появляться на экране первым.
  • Основной контент должен появиться на экране за 1000 мс или меньше (другие элементы страниц могут появиться на экране позже).
  • «Даже отказ должен выглядеть хорошо»: если некая функциональность отказывает, это не должно мешать другим компонентам страницы и ее отображению, а пользователь должен получить основной контент.

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

Различные виджеты, сайдбары и рекламные баннеры подождут своей очереди.

Архитектурное решение

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

Хаманн обращает внимание, что в обычном блоге на типичной платформе как WordPress могут происходить до 8-ми обращений к базе данных, чтобы показать пользователю страницу со статьей.

Каждое такое обращение «съедает» часть бюджета времени. Это особенно заметно, когда бюджет времени — всего 1 секунда.

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

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

Поэтому архитектура страницы была изменена, как показана на рисунке ниже.

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

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

Загрузка за 1 секунду

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

Guardian обращает внимание и на мобильных пользователей, доля которых постоянно растет. У них ситуация с загрузкой страниц хуже, чем у пользователей, подключенных к быстрому интернету в доме и офисе. Последовательность работы браузера до отображения страницы выглядит так (слайд из Google Page Insights):

При среднем 3G-соединении 600 мс уже заняты той частью, которая связана с сетевой частью, и тут в принципе разработчик сайта сделать ничего не может: это обращение к DNS, TCP-соединение и GET-запрос, чтобы получить страницу и получение этой страницы. И 600 мс – это минимум. На некоторых 3G-сетях вообще не удастся уложиться в требование показа основного контента за 1 секунду.

У разработчика остается только 400 мс, на которые он может повлиять – например, оптимизируя сервер или правильно структурируя страницу.

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

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

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

Поэтому команда стала включать критически важные стили, связанные с отображением основного контента в html-файлы страниц.

В конце документа остальные стили загружаются асинхронно.

Этот метод идет против лучших практик, но его результат в плане ускорения загрузки поражает, команда сэкономила порядка 500 мс за счет того, что включила базовый CSS в html-документ.

Кроме того, команда стала использовать хранение стилей на машине пользователя для ускорения загрузки последующих страниц.

Подход к шрифтам

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

Однако в Guardian фирменный шрифт, специально разработанный для этого издания, считается значительной частью бренда. В проведенных тестах пользователи легко угадывали страницу Guardian, где не было никаких элементов бренда, только текст, набранный фирменным шрифтом. Guardian cчитает это важным преимуществом, и не хочет от этого отказываться.

Поэтому команда Хаманна применила следующий алгоритм работы со шрифтом: если браузер пользователя современный, и поддерживает WOFF, то фирменный шрифт асинхронно скачивается в локальный кэш на диске пользователя и показывается далее оттуда. Сам шрифт кодируется в base-64 в json-файле.

Такой подход обеспечивает всего один http-запрос.

Результат

В итоге после всех указанных модификаций цель – показывать основной контент за 1 секунду была выполнена, а полное время загрузки сайта сократилось с 12,1 с до 3,2 с.

В заключение повторим основные рекомендации Патрика Хаманна:

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