1 / 60

«Вечная статика» оптимизация отдачи контента

«Вечная статика» оптимизация отдачи контента. Сергей Скворцов. 2011-0 4 -26. I. Теория. Стороны и связь. Браузер отображение/рендеринг страниц/данных Протокол передача данных: запрос-ответ или stream Сервер приём запросов, формирование и передача ответов. Скорость показа контента.

Télécharger la présentation

«Вечная статика» оптимизация отдачи контента

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. «Вечная статика»оптимизация отдачи контента Сергей Скворцов 2011-04-26

  2. I. Теория

  3. Стороны и связь • Браузер • отображение/рендеринг страниц/данных • Протокол • передача данных: запрос-ответ или stream • Сервер • приём запросов, формирование и передача ответов

  4. Скорость показа контента • Скорость отображения в браузере • Скорость передачи по сети • Скорость ответа от сервера

  5. 1)Скорость отображения в браузере • Рендеринг / вёрстка • Встраивание ресурсов/данных • Data URI, CSS sprites • увеличивает размер ответа • AJAX, WebSockets • Отложенная загрузка;Prefetching • JavaScript: async/defer; post-load

  6. 1.1)Рендеринг/вёрстка • Корректный порядок указания ресурсов (JS/CSS) • Yahoo «Best Practices for Speeding Up Your Web Site» • Самоограничения: CSSexpressions • Прогрессивная вёрстка • см. StoyanStefanov (Yahoo) • Верстка независимыми блоками • см. Виталий Харисов (Яндекс) • Шаблоны на client-side (XSLT)

  7. 2)Скорость передачи по сети • Каналы… • … связность, распределение по странам, ДЦ • DNS-resolving • Уменьшение числа lookup’ов (число хостов, TTL) • Geo-balancing, IP anycast • Постоянные соединения • HTTP 1.0 keep-alive == HTTP 1.1 persistent

  8. 2)Скорость передачи по сети • Раздача с нескольких хостов • CDN; DNS/geo-balancing, TCP anycast • Параллелизация загрузки: default лимит у браузеров – не более 6 запросов на хост • JS-хостинги (для jQuery, YUI, …) • 13% страниц используют Google Libraries API • Хорошо кэшируютсямежду сайтами • Privacy: источник Referer’ов для поисковиков

  9. 2)Скорость передачи по сети • HTTP pipelining - не популярен • Дружим с proxy-servers, и ненавидим их • Кэширование! • Их 10% запросов (оценка по Openstat.Trends) • «Над»-протоколы (HTTPS, SPDY) • HTTPS – безопасность, но overhead • SPDY – только Google, нет поддержки в nginx :)

  10. 3)Скорость ответа от сервера • Скорость генерации ответа • Уменьшение размера ответа • Уменьшение размера запроса • Уменьшение числа запросов

  11. 3.1) Скорость генерации ответа • Хорошие frontend’ы • Быстрые серверы приложений (backend’ы) • Прогрессивная отдача контента • flush() • Кэширование: • данных (memcached) • ответа (mod_cache*)

  12. 3.2)Уменьшение размера ответа • Сжатие ответа • ngx_http_gzip, ngx_http_gzip_static • mod_gzip, mod_deflate • Отложенная «подгрузка» JS, контента • Post-loading

  13. 3.2)Уменьшение размера ответа • Оптимизация содержимого (minification) • Оптимизация JS/CSS • Closurecompiler, YUI Compressor • Оптимизация графики • Оптимизация HTML • Пробелы, комментарии, default атрибуты, … • htmlcompressor,или при компиляции шаблонов 

  14. 3.3)Уменьшение размера запроса • Отдача статики в другом домене • Чтобы не слать лишние заголовки: Cookie • Уменьшаем размер Cookie • FYI: максимальный суммарный размер на домен: • Firefox, Chrome - no limit • Opera, IE6 - 4096байт • IE8 - 10234байт

  15. 3.4)Уменьшение числазапросов • Кэширование контента на стороне браузера • Объединение стилей и скриптов (JS, CSS) • Объединение и внедрение картинок(CSS sprites, Data URI, MHTML) • ценой большего размера ответа • Избегать редиректов

  16. Итого • Всё вышеописанное можно использовать как checklist, варианты ответов: • Уже так делаем • Не делаем, потому что (программисты|админы) сказали что… • Не знали / совсем забыли – надо подумать

  17. II. Приём

  18. Как работает кэширование в HTTP • При первом запросе к ресурсу браузер: • Запоминает заголовки ответаLast-Modified и/ли ETag • Определяет сколько времени можно не обращаться к серверу, а использовать локальный кэш - на основе данных из заголовков: • Expires • Cache-Control http://www.w3.org/Protocols/HTTP/1.1/rfc2616bis/

  19. Как работает кэширование в HTTP • При втором запросе к серверу: • Если ресурс в локальном кэше – браузер делает валидацию – шлёт условный запрос: • If-Unmodified-Sinceи/ли If-None-Match • Если ресурс не менялся (304 Not modified):ждём опять expiration

  20. Нюансы де-факто • По факту ETagиспользуетсядля статики так: • nginx: не вычисляет вообще • Apache:inode-size-timestamp • IIS:Filetimestamp:ChangeNumber • Это не работает на кластере машин • inodeи ChangeNumberбудут разные

  21. Проблемы этого дня • Заголовки ExpiresиCache-Control: max-age тупо не выставляют • 56% запросов вообще не указывают expiration • 24% запросов может кэшироваться http://www.stevesouders.com/blog/2011/04/18/http-archive-max-ag/ • Нопри этом есть статика – которая меняется редко: • CSS, JavaScript, картинки, Flash, иконки (!)

  22. Проблемы этого дня • Поскольку нет expiration – каждый раз шлётся запрос (в надежде на 304 Not modified) • Но такой запрос это: • Минимум 2 IP пакета • Время на ожидание ответа • Особенно печально ждать когда блокируемся на рендеринге

  23. Решение: выставлять expiration • Выставлять expiration для динамики несложно (семантику знает backend) • Но любой константный expiration для статики приводит к проблемам при обновлении сайта (новый дизайн, шаблоны, …) • Единый глобальный Expire - выставить нельзя • Выход: версионированиена уровне URI

  24. Версионирование • Наивный подход – добавлять «?» + timestamp: /favicon.ico?ver=3 • Многие прокси серверы считают URL с «?» некэшируемым в принципе • Не учитываются зависимости внутри ресурса: • /style.css?ver=3ссылается внутри на /logo.png?ver=5

  25. Версионирование: верный подход • Добавляем версию внутрь пути: /favicon_1303591683.ico • Версию можно брать из VCS, но не каждый ресурс лежит в репозитории, он может создаваться при выкатке • Очевидный вариант – timestamp • Для файлов с зависимостями «наружу» – считаем версию с учётом зависимостей, пример: md5( timestamp + @versioned_dependencies_urls) • Экономим байты – используя Base64 URLSafe

  26. Обработка внешних зависимостей • Делаем общий префикс /s/в URLах статики • Для всех шаблонов, которые ссылаются на версионированную статику, обновляем ссылки • Всё! Статика стала вечной, поэтому: location /s/ { expires max; gzip_static on; }

  27. Применимость • Стоит применять для: • Файлов стилей и скриптов (CSS, JS) • Картинок, являющихся частью дизайна/шаблона • Flash-объектов • Не надо применять для: • Скачиваемых файлов (и подлежащих индексации) • Особо актуально: • Мобильные сайты

  28. Немного статистики:число запросов

  29. mime-types:по числу запросов

  30. mime-types:медиана размера ответа

  31. HTTP Archive:медиана размера ответа http://httparchive.org/interesting.php#responsesizes

  32. III. Практика

  33. Htdocs layout • На файловой системе: htdocs/ frontend/ eternal/ backend/ • frontend - статика, отдаётся nginx • eternal– «вечная» статика, отдаётся nginx • backend - шаблоны, используются в upstream

  34. VCS layout • В репозитории: trunk/ htdocs-frontend/ a/ css/ img/ js/ htdocs-backend/

  35. Сборка пакетов: шаги • Checkout • Processing • Стадия «generate» • Стадия «preprocess» • Стадия «optimize» • Стадия «produce» • Генерация «вечной статики» (кладём в /s/) • Packing distfiles

  36. Сборка пакетов – Processing • Стадия «generate» • Генерация новых файлов, на основе checkout’а • img2css– набор иконок в один CSS файл • Стадия «preprocess» • Изменение содержимого файла, и/ли метаданных о нём • inline-includes– объединение файлов • CSS: раскрытие @import • JavaScript: раскрытие _include_js()

  37. Сборка пакетов – Processing • Стадия «optimize» • Оптимизация формата файла, с сохранением инварианта его семантики • yuicompressor– JS/CSS minification • Стадия «produce» • Генерация других файлов на основе итоговых • gzip_static– создание сжатой версии статики

  38. Сборка пакетов – «вечная» статика • Конфигурация: <handler name="eternal-static" process_path="/a/" target_path="/s/" match_ext="gif icojpg pngswfjscss" expand_ext="jscss" />

  39. Сборка пакетов – «вечная» статика • Сканируем директорию process_pathна предмет статических файлов с нужными расширениями • Обрабатываем раскрываемые файлы (*.js *.css) на предмет ссылок на другие найденные ранее статические файлы • Строим граф зависимостей

  40. Сборка пакетов – «вечная» статика • В директории target_pathсоздаём соотв. версии статических файлов (и их gzipped-версий, если у файлов был handlergzip_static) • Итоговый файл будет называтьсяfilename_revision.ext, где revision – ревизия файла /a/file.txt /s/file_REVISION.txt

  41. Сборка пакетов – «вечная» статика • Для статического файла, который не имеет зависимостей (в т.ч. тех, которые не раскрываются вообще, типа картинок), ревизия равна mtime • VCS ревизия может быть недоступна, если файл генерировался. • При генерации файлов mtimeфинального файла всегда равен максимальному mtimeего исходных файлов

  42. Сборка пакетов – «вечная» статика • Для статического файла, который имеет зависимости, ревизия вычисляется как md5( join('\0', mtime, sort@eternal_static_deps) ) - т.е. создаётся семантически уникальная ревизия файла. • Жёсткое создание ревизии (md5 от тела файла) не используется, чтобы при изменениях контента, которые семантически инвариантны (например, применён новый алгоритм оптимизации/obfuscation файлов) не создавалась новая ревизия.

  43. Сборка пакетов – «вечная» статика • Создаём файл /s/.mapping, который содержит строки с парами "статический файл", "вечно-статический файл": /a/js/base.js /s/js/base_iv6uTQ.js /s/css/main.css /s/css/main_msy5mT8H-Ak6hBAsce-30w.css

  44. Пример: www.openstat.ru <!DOCTYPE HTML><html lang="ru"><head> <title>Интернет-статистика и веб-аналитика | Openstat: Независимая аналитика</title> <link rel="stylesheet" type="text/css" href="/s/css/main_msy5mT8H-Ak6hBAsce-30w.css" /> <script type="text/javascript" src="/s/js/base_iv6uTQ.js"></script>

  45. Установка пакетов • Файлы ставятся в share/htdocs/frontend • На этапе POST-INSTALL запускаем: rsync -rlptgoD--checksum--delete-after share/htdocs/frontend htdocs/frontend • Это делается для того, чтобы при удалении пакета в htdocs/frontendчто-то оставалось

  46. Установка пакетов • Также копируем вечную статику: rsync -rlptgoD--checksum htdocs/frontend/s/ htdocs/eternal • В htdocs/eternalфайлы никогда не удаляются!

  47. Установка пакетов • Раскрываем(и атомарно замещаем) файлы шаблонов по списку из /s/.mapping:htdocs/backend • Поскольку директория /a/также ставится, то задержка в раскрытии файлов, равно как их нераскрытиене влияет фатально на работу сайта - просто запросы пойдут к "менее вечной" статике.

  48. Конфигурация frontend’а • Пример для обычного веб-сервера: location ^~ /s/ { alias htdocs/eternal; gzip_static on; expires max; }

  49. Соглашения • Соглашения для раскрываемых файлов: • Полное указание пути на ссылаемые файлы • В JS не использовать составление URLиз частей , прописывать в коде полностью(как hash)

More Related