Статьи Доклады с конференций

Автор: Николай Мациевский aka sunnybear
Презентация в .ppt

Разгоняем все, что движется

Оптимизация времени загрузки сайта: проблемы и решения

Большинство сайтов Рунета работают :) Почти всегда. И почти всегда медленно. Иногда причина этого — плохой канал связи у конечного пользователя или самого сайта. Но ни веб-разработчики, ни онлайн-маркетологи зачастую не отдают себе отчет, насколько эту ситуацию можно изменить, и изменить кардинально.

Основные методы

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

  • Уменьшение объема данных: большое число методов по минимизации и архивированию.
  • Уменьшение числа запросов: основная технология — CSS Sprites.
  • Кеширование.
  • Параллельные загрузки.
  • Оптимизация JavaScript.

Обзор аудитории

Основным критерием, который должен определять, какие методы и в каком объеме стоит применять, естественно, будет аудитория ресурса. Для каждого сайта можно выделить несколько характерных групп страниц, которые посещаются тем или иным типом аудитории. В первую группу войдут веб-страницы, на которые заходят всякий раз новые пользователи. Это и специальные рекламные страницы, задачей которых является прямая продажа продукта. Это и страницы объявлений, которые пользователи должны увидеть один, максимум, два раза. И т.д. Аудитория таких страниц на 99,9% состоит из новых пользователей. Следовательно, для них нужно применять методы, снижающие, в первую очередь, число обращений к серверу для показа страницы: объединение файлов и экстремальную оптимизацию.

Во вторую группу войдут страницы, аудитория которых также часто меняется, однако, часть ее может просматривать страницы неограниченное число раз. Для таких страниц можно выделить характерное ядро постоянных посетителей, однако, оно составляет не более 30–40% от общего числа. Большинство сайтов, которые «живут» на поисковом трафике, являются замечательным примером ресурсов, полностью подходящих под эту группу. Для таких сайтов, в первую очередь, стоит рассмотреть методы уменьшения числа запросов (CSS Sprites), также возможную минимизацию всех текстовых файлов (HTML, CSS, JS). Однако, применение кеширование в данном случае оправдано в меньшей степени, так как уменьшит время загрузки страницы не так сильно (если брать средневзвешенное значение), чем, например, параллельные запросы.

Наконец, к третьей группе можно отнести все остальные страницы, а именно те, аудитория которых в большей степени постоянна (конкретные числа стоит рассматривать из параметров монетизации различных групп аудитории, однако, характерные значения здесь — это 30% постоянных пользователей ресурса). В этой группе наиболее действенным будет, конечно же, кеширование и оптимизация скорости работы JavaScript и Flash-анимации — ведь именно она будет «съедать» больше всего времени у характерного пользователя такой аудитории.

Уменьшение объема данных: сжатие и архивирование

Основными инструментами для уменьшения объема данных являются разнообразные минимизаторы и обфускаторы (для JavaScript-файлов), архивирование и также ряд утилит для уменьшения размера изображений. Давайте рассмотрим их по порядку.

График сжатия CSS-файлов

Как показало проведенное тестирование средств сжатия CSS, лучше всего с этой задачей справляется проект CSS Tidy (примерно на одном уровне с ним идет YUI Compressor), который вместе с дополнительным архивированием файлов позволяет получить выигрыш до 85%.

График сжатия JS-файлов

Для JavaScript-файлов ситуация несколько интереснее. Если применять архивирование, то лучше всего использовать YUI Compressor, так как он, в среднем, сжимает в этом случае лучше. Если архивирование для JS-файлов применять нельзя, то лидером в сжатии является Dean Edwards Packer, однако, он вносит дополнительные издержки на свою «распаковку». Как показали исследования, для пользователей, которые будут, в основном, загружать JavaScript из кеша, лучше использовать сжатие без обфускации.

Использование архивирования через mod_gzip для Apache способно существенно уменьшить размер загружаемых файлов. Однако, в случае очень быстрого канала у пользователей (например, локальный ресурс) и ограниченных ресурсов сервера (высокая удельная нагрузка на создание страницы) будет разумнее сжатие не использовать.

Накладные издержки на сжатие и передачу информации для 100Кб и 1500Кб и 280МГц и 1000МГц

Также стоит для архивированных файлов добавить соответствующие заголовки (Cache-Control:private), чтобы избежать ряда проблем с кеширующими прокси-серверами. Для архивирования CSS- и JS-файлов также нужно исключить Safari и Konqueror из тех браузеров, которым можно отправлять gzip-файлы: эти браузеры до последнего времени не умели их корректно распознавать.

Уменьшение размера изображений

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

Сейчас существует проблема с поддержкой альфа-канала в Internet Explorer (которую уже исправили в 7 версии), однако, в версиях ниже 7 (5.5 и 6) она решается через ImageAlphaLoader (с помощью CSS expressions, CSS хаков или JavaScript), что позволяет использовать полупрозрачность, практически, в полном объеме.

В случае проблем с совпадением цветом (опять-таки в Internet Explorer) рекомендуется удалить из изображения gamma-чанков. В этом также может помочь ряд утилит, уменьшающих размер PNG-изображений: например, pngcrush. Для уменьшения размера JPG-изображений можно применить утилиту jpegtran, которая не затрагивает цветовые данные изображения, а удаляет комментарии и другие мета-данные.

Для анимированных изображений стоит использовать либо GIF-изображения с несколькими кадрами, либо DHTML-анимацию (JavaScript + PNG/JPEG).

Семантическая верстка

Когда разговор заходит про уменьшение размера кода, очень часто забывают про переход на семантическую разметку вместо табличной. Однако, она способна уменьшить не только время разработки backend-логики за счет более прозрачной структуры блоков, но и «облегчить» frontend-часть, сократив размер HTML примерно на 30%.

Сразу хочу заметить, что строгое следование семантике может отрицательно сказаться на размере кода, поэтому вам придется решить, что для вас важнее: поддержка последних тенденций (например, из мира микроформатов) или скорость загрузки страницы, например, интернет-магазина. Возможно, в ряде случаев будет разумно применить более простую спецификацию, сократив тем самым общее количество тегов и размер картинок (для CSS Sprites).

Уменьшение числа запросов

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

@media тип {селекторы для этого типа}

например,

@media print {.nonprintable{display:none}}.

Для уменьшения числа JS-файлов у нас гораздо больше простора для фантазии. Можно просто создать один большой файл со всеми используемыми вызовами и библиотеками. Можно создать один внешний файл, который будет загружать библиотеки по мере необходимости. А можно с помощью комбинированного обработчика событий window.onload начать загрузку всех необходимых файлов сразу по получению HTML-кода.

Используя технику «ненавязчивый» JavaScript можно добиться существенного визуального ускорения при загрузке сложного интерфейса или веб-страниц с нетривиальной логикой.

CSS Sprites

Наиболее популярной техникой для объединения изображений является CSS Sprites (или CSS Image maps), когда для отображения нескольких (десятков или даже сотен) изображений используется один ресурсный файл. Она дает ощутимый выигрыш в скорости загрузки при использовании анимационных эффектов (например, смене изображения при наведении мыши), а также при большом количестве иконок на странице.

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

  • Разбиение всех изображений на 5 основных групп (не рекомендуется использовать в одном файле изображений из более, чем 2 групп):
    • Изображения, повторяющиеся по всем направлениям (repeat).
    • Изображения, повторяющиеся по горизонтали (repeat-x).
    • Изображения, повторяющиеся по вертикали (repeat-y).
    • Изображения, которые не повторяются (no-repeat).
    • И анимированные изображения.
  • Размер файлов должен быть не более 10–20 Кб.
  • Объединение близких по цветовой гамме изображений.

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

Экстремальная оптимизация

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

В качестве характерного примера использования таких техник можно примести главные страницы Яндекса и Yahoo!, на которых CSS- И JS-файлы кроме стандартной минимизации еще и включены в итоговый HTML-код, а сам HTML отдается в виде gzip-архивов.

Логическим продолжением в данном случае будет использование схемы data:URL и base64-кодирования для подключения фоновых и обычных изображений. Результирующий размер gzip-файла увеличится на 5–10% (от размера изображения), однако, при этом удастся сэкономить один запрос к серверу. С помощью несложных вычислений можно подсчитать, при каком размере файла это рационально применять.

Однако, Internet Explorer не поддерживает эту технику (до версии 7 включительно). Для него можно использовать специальные хаки (в том числе, * html), условные комментарии или mhtml-схему, которая обеспечивает, практически, ту же функциональность, что и data:URL.

Кеширование

Основной техникой для ускорения загрузки страницы для постоянных посетителей является кеширование, которое может свести число запросов к серверу для отображения страницы к минимуму (в идеале, к нулю). Здесь стоит помнить о корректной настройке заголовка Cache-Control. Для сброса кеша всегда можно воспользоваться дополнительным параметром в GET-запросе к ресурсу, который заставит сервер взять тот же физический файл, а клиентский браузер запросить файл и сохранить его под новым именем. Для статических ресурсов стоит выставлять достаточно большой срок кеша (можно экспериментировать со значения от месяца), для остальных файлов это значение должно быть равно среднему времени изменения либо вообще отсутствовать (для HTML-файлов, например).

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

Параллельные загрузки

Для уменьшения удельного времени ответа от сервера при загрузке большого числа файлов можно разделить загрузку на несколько потоков (серверов). Сами сервера для такой цели (быстрой отдачи статических ресурсов) лучше настраивать под «легким» окружением (например, nginx). В качестве балансирующего параметра можно рассматривать как распределение по географическому принципу (например, кластеры в США, Европе, Азии), так и по нагрузке (пул свободных серверов определяется каждый раз при загрузке страницы). Также возможно использование балансировки на клиенте для достижения того же эффекта.

В качестве основных проблем стоит отметить необходимости создания хеш-функции от имени файла, чтобы один и тот же файл загружался только с одного сервера, иначе браузер будет запрашивать его с серверов-зеркал, пока не забьет кеш всеми его копиями. Также стоит ограничиться 4 хостами (для большого числа файлов), для небольшого (15–25) стоит использовать не более 3. 2 хоста разумно использовать, только если число файлов превосходит 10 из-за дополнительных расходов на распознавание имени в DNS-таблице.

Оптимизация JavaScript

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

Используйте возможности CSS по максимуму. Вы не сможете отобразить страницу в браузере лучше, чем сам браузер, поэтому оставьте всю тяжелую работу по рендерингу для него (это относится к анимационным эффектам при наведении на кнопки, изменению разметки при изменении размеров окна и т.д.). CSS-движок, в среднем, работает быстрее, чем JavaScript. Также посоветую избегать использования CSS expressions либо оптимизировать их, чтобы они исполнялись только один раз на странице.

Обновляйте DOM-дерево большими кусками. DOM-Обращения ресурсоемки, это почти как база данных для серверных приложений. Чем меньше будет у вас работы с DOM, тем быстрее будет ваш JavaScript. Отдельное слово по поводу обработчиков событий: сводите их количество к минимуму. В идеале, стоит повесить один-единственный onclick на «body» и обрабатывать уже источник клика. Если вам требуются менее глобальные эффекты — просто ограничьтесь одним обработчиков на блоке, в котором заключена требуемая область. Большое количество обработчиков событий (которые еще и забывают убирать из изменении HTML-кода на странице) приводит к утечкам памяти в IE.

И несколько общих советов: кешируйте глобальные переменные в локальные (однако, тут могут быть нюансы, особенно с цепочками вызовов функций), избегайте использовать eval и setTimeout / setInterval (которые выполняют eval на передаваемую в качестве аргумента строку). Вместо этого можно использовать анонимные функции.

(function(){ ... }())

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

Действенность методов

Что же из всего вышеперечисленного больше всего влияет на скорость загрузки? Как я уже упоминал, это сильно зависит от типа оптимизируемых страниц, однако, можно выделить некоторые общие тенденции. Так, кеширование позволяет снизить время загрузки страницы вплоть до нуля (чтобы она полностью загружалась из браузерного кеша пользователя, а ведь на ней может быть реклама, которую пользователь увидит, не заходя физически к вам на сайт).

Использование нескольких серверов для параллельных запросов способно уменьшить время загрузки на где-то 85%, использование CSS Sprites — на 60%. Объединение текстовых файлов и их минимизация, в среднем, дает 40% выигрыш (однако, если у вас сложное веб-приложение, в котором функционирует десятки JavaScript-библиотек, то такая техника способно в разы ускорить его работу).

Оптимизация изображений уменьшает их удельный вес примерно на 30%. Если вы займетесь оптимизацией JavaScript-кода и вызовов функций, то сэкономите около 20%. Семантическая верстка способна уменьшить время загрузки только лишь на 10% (это связано с тем, что удельный вес HTML-кода в объеме страницы очень мал, поэтому больший выигрыш дает простое архивирование).

Что дадут оптимизационные мероприятия вашему бизнесу? По данным Yahoo! замедление страниц Google на 500мс приводит к 20% потере трафика, для Amazon 100мс обходятся в 1% продаж. Недавно проведенная оптимизация главной страницы европейского сайта Acronis (время загрузки было уменьшено почти в 5 раз) привело примерно к 5% росту продаж и такому же увеличению трафика на внутренние страницы.

Также оптимизационные мероприятия позволили ускорить загрузку сайта www.pmexpert.ru в 2,8 раза, а www.creative.su в 2,6 раза

Профилирующие инструменты для оптимизации

Лучшим в своем классе профилирующим инструментом для оценки скорости загрузки сайта а анализа узких мест является Yslow под Firebug для Firefox). С помощью него можно установить и отладить, практически, все, что требуется для ускорения загрузки сайта. Основным его минусом является невозможность посмотреть, как именно происходит загрузка из кеша и, естественно, распространение только под Firefox (хотя, может быть, это является и плюсом).

Недавно AOL выпустило PageTest для Internet Explorer'а (6 и 7), который также позволяет увидеть диаграмму загрузки сайта, однако, не выдает таких развернутых советов, как YSlow. Для нахождения утечек памяти и замыканий под IE можно воспользоваться Drip.

JsUnit предоставляет мощный framework для тестирования и отладки ваших JavaScript-приложений. С помощью AjaxView можно проксировать и анализировать AJAX-запросы. Для профессионального профилирования веб-приложений стоит воспользоваться JsLex, а время выполнения различных операций на странице можно замерить с помощью YUI Profiler. Но не забывайте, что лучшей проверкой ваших приложений на прочность всегда был и остается пользователь.

Наконец, пара слов об онлайн-инструментах. Пожалуй, самым старым и профессиональным можно назвать WebSiteOptimizator, который получает данные о всех требуемых для загрузки страницы файлах и выдает ряд советов по оптимизации времени загрузки. Также есть ряд сервисов (OctaGate SiteTimer и Pingdom Tools), которые отображают диаграмму загрузки сайта в режиме онлайн. Однако, на них практически отсутствуют советы по оптимизации скорости загрузки.

В отличие от вышеуказанных инструментов, Web Optimizator позволяет как получить сведения о всех загружаемых файлах и большое количество подробных советов (что же с этими файлами можно и нужно сделать) так и посмотреть, как эти файлы будут загружаться в различных браузерах. И что более важно, применять ряд оптимизационных методов «не отходя от кассы», т.е. прямо на диаграмме загрузки. При этом не нужно ничего настраивать на сервере и проверять, уменьшится ли время загрузки после определенных действий или нет — все можно осуществить в режиме онлайн.

Спасибо за внимание. Буду рад ответить на ваши вопросы.

Все комментарии (habrahabr.ru)