eternal static (rit 2011)

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

Upload: sergey-skvortsov

Post on 13-Dec-2014

461 views

Category:

Technology


0 download

DESCRIPTION

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

TRANSCRIPT

Page 1: Eternal static (RIT 2011)

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

Сергей Скворцов

2011-04-26

Page 2: Eternal static (RIT 2011)
Page 3: Eternal static (RIT 2011)

3

I. ТеорияI. Теория

Page 4: Eternal static (RIT 2011)

Стороны и связь1. Браузер– отображение/рендеринг страниц/данных

2. Протокол– передача данных: запрос-ответ или stream

3. Сервер– приём запросов, формирование и передача

ответов

Page 5: Eternal static (RIT 2011)

Скорость показа контента

1. Скорость отображения в браузере

2. Скорость передачи по сети

3. Скорость ответа от сервера

Page 6: Eternal static (RIT 2011)

1) Скорость отображения в браузере

• Рендеринг / вёрстка• Встраивание ресурсов/данных– Data URI, CSS sprites

• увеличивает размер ответа

– AJAX, WebSockets• Отложенная загрузка; Prefetching– JavaScript: async/defer; post-load

Page 7: Eternal static (RIT 2011)

1.1) Рендеринг/вёрстка• Корректный порядок указания ресурсов (JS/CSS)

– Yahoo «Best Practices for Speeding Up Your Web Site»

• Самоограничения: CSS expressions• Прогрессивная вёрстка

– см. Stoyan Stefanov (Yahoo)

• Верстка независимыми блоками– см. Виталий Харисов (Яндекс)

• Шаблоны на client-side (XSLT)

Page 8: Eternal static (RIT 2011)

2) Скорость передачи по сети• Каналы…– … связность, распределение по странам, ДЦ

• DNS-resolving– Уменьшение числа lookup’ов (число хостов, TTL)– Geo-balancing, IP anycast

• Постоянные соединения– HTTP 1.0 keep-alive == HTTP 1.1 persistent

Page 9: Eternal static (RIT 2011)

2) Скорость передачи по сети

• Раздача с нескольких хостов– CDN; DNS/geo-balancing, TCP anycast – Параллелизация загрузки: default лимит у

браузеров – не более 6 запросов на хост– JS-хостинги (для jQuery, YUI, …)

• 13% страниц используют Google Libraries API– Хорошо кэшируются между сайтами

• Privacy: источник Referer’ов для поисковиков

Page 10: Eternal static (RIT 2011)

2) Скорость передачи по сети

• HTTP pipelining - не популярен• Дружим с proxy-servers, и ненавидим их– Кэширование!– Их 10% запросов (оценка по Openstat.Trends)

• «Над»-протоколы (HTTPS, SPDY)– HTTPS – безопасность, но overhead– SPDY – только Google, нет поддержки в nginx :)

Page 11: Eternal static (RIT 2011)

3) Скорость ответа от сервера

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

Page 12: Eternal static (RIT 2011)

3.1) Скорость генерации ответа

• Хорошие frontend’ы• Быстрые серверы приложений (backend’ы)• Прогрессивная отдача контента – flush()

• Кэширование:– данных (memcached)– ответа (mod_cache*)

Page 13: Eternal static (RIT 2011)

3.2) Уменьшение размера ответа

• Сжатие ответа – ngx_http_gzip, ngx_http_gzip_static – mod_gzip, mod_deflate

• Отложенная «подгрузка» JS, контента– Post-loading

Page 14: Eternal static (RIT 2011)

3.2) Уменьшение размера ответа

• Оптимизация содержимого (minification) – Оптимизация JS/CSS

• Closure compiler , YUI Compressor

– Оптимизация графики– Оптимизация HTML

• Пробелы, комментарии, default атрибуты, …• htmlcompressor , или при компиляции шаблонов

Page 15: Eternal static (RIT 2011)

3.3) Уменьшение размера запроса

• Отдача статики в другом домене – Чтобы не слать лишние заголовки: Cookie

• Уменьшаем размер Cookie– FYI: максимальный суммарный размер на домен:

• Firefox, Chrome - no limit• Opera, IE6 - 4096 байт• IE8 - 10234 байт

Page 16: Eternal static (RIT 2011)

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

• Кэширование контента на стороне браузера• Объединение стилей и скриптов (JS, CSS)• Объединение и внедрение картинок

(CSS sprites, Data URI, MHTML)– ценой большего размера ответа

• Избегать редиректов

Page 17: Eternal static (RIT 2011)

Итого

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

сказали что…– Не знали / совсем забыли – надо подумать

Page 18: Eternal static (RIT 2011)

18

II. ПриёмII. Приём

Page 19: Eternal static (RIT 2011)

Как работает кэширование в HTTP

• При первом запросе к ресурсу браузер:– Запоминает заголовки ответаLast-Modified и/ли ETag

– Определяет сколько времени можно не обращаться к серверу, а использовать локальный кэш - на основе данных из заголовков:• Expires• Cache-Control

http://www.w3.org/Protocols/HTTP/1.1/rfc2616bis/

Page 20: Eternal static (RIT 2011)

Как работает кэширование в HTTP

• При втором запросе к серверу:– Если ресурс в локальном кэше – браузер делает

валидацию – шлёт условный запрос:• If-Unmodified-Since и/ли If-None-Match

– Если ресурс не менялся (304 Not modified):ждём опять expiration

Page 21: Eternal static (RIT 2011)

Нюансы де-факто

• По факту ETag используется для статики так:– nginx: не вычисляет вообще– Apache: inode-size-timestamp– IIS: Filetimestamp:ChangeNumber

• Это не работает на кластере машин– inode и ChangeNumber будут разные

Page 22: Eternal static (RIT 2011)

Проблемы этого дня• Заголовки Expires и Cache-Control: max-age тупо не выставляют– 56% запросов вообще не указывают expiration– 24% запросов может кэшироваться http

://www.stevesouders.com/blog/2011/04/18/http-archive-max-ag/

• Но при этом есть статика – которая меняется редко:– CSS, JavaScript, картинки, Flash, иконки (!)

Page 23: Eternal static (RIT 2011)

Проблемы этого дня

• Поскольку нет expiration – каждый раз шлётся запрос (в надежде на 304 Not modified)

• Но такой запрос это:– Минимум 2 IP пакета– Время на ожидание ответа

• Особенно печально ждать когда блокируемся на рендеринге

Page 24: Eternal static (RIT 2011)

Решение: выставлять expiration

• Выставлять expiration для динамики несложно (семантику знает backend)

• Но любой константный expiration для статики приводит к проблемам при обновлении сайта (новый дизайн, шаблоны, …)

• Единый глобальный Expire - выставить нельзя• Выход: версионирование на уровне URI

Page 25: Eternal static (RIT 2011)

Версионирование

• Наивный подход – добавлять «?» + timestamp: /favicon.ico?ver=3

– Многие прокси серверы считают URL с «?» некэшируемым в принципе

– Не учитываются зависимости внутри ресурса:• /style.css?ver=3 ссылается внутри на /logo.png?ver=5

Page 26: Eternal static (RIT 2011)

Версионирование: верный подход• Добавляем версию внутрь пути: /favicon_1303591683.ico

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

– Очевидный вариант – timestamp

• Для файлов с зависимостями «наружу» – считаем версию с учётом зависимостей, пример:

md5( timestamp + @versioned_dependencies_urls)

• Экономим байты – используя Base64 URLSafe

Page 27: Eternal static (RIT 2011)

Обработка внешних зависимостей• Делаем общий префикс /s/ в URLах статики• Для всех шаблонов, которые ссылаются на

версионированную статику, обновляем ссылки• Всё! Статика стала вечной, поэтому:

location /s/ { expires max; gzip_static on;}

Page 28: Eternal static (RIT 2011)

Применимость• Стоит применять для:• Файлов стилей и скриптов (CSS, JS)• Картинок, являющихся частью дизайна/шаблона• Flash-объектов

• Не надо применять для:• Скачиваемых файлов (и подлежащих индексации)

– Особо актуально:• Мобильные сайты

Page 29: Eternal static (RIT 2011)

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

20071%301

1%

3022%

30422%

4043%

Page 30: Eternal static (RIT 2011)

mime-types: по числу запросовimage/jpeg 22%image/gif 14%image/png 6%application/javascript 3%text/css 2%text/plain 2%image/x-icon 1%application/x-shockwave-flash 1%

Page 31: Eternal static (RIT 2011)

mime-types: медиана размера ответаimage/jpeg 26 694image/gif 5 268image/png 18 161application/javascript 19 769text/css 7 100text/plain 71 184image/x-icon 3 210application/x-shockwave-flash 220 566

Page 32: Eternal static (RIT 2011)

HTTP Archive: медиана размера ответа

http://httparchive.org/interesting.php#responsesizes

Page 33: Eternal static (RIT 2011)

33

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

Page 34: Eternal static (RIT 2011)

Htdocs layout• На файловой системе:

htdocs/ frontend/ eternal/ backend/

• frontend - статика, отдаётся nginx• eternal – «вечная» статика, отдаётся nginx• backend - шаблоны, используются в upstream

Page 35: Eternal static (RIT 2011)

VCS layout• В репозитории:

trunk/ htdocs-frontend/ a/ css/ img/ js/ htdocs-backend/

Page 36: Eternal static (RIT 2011)

Сборка пакетов: шаги

1. Checkout2. Processing

1. Стадия «generate»2. Стадия «preprocess»3. Стадия «optimize»4. Стадия «produce»5. Генерация «вечной статики» (кладём в /s/)

3. Packing distfiles

Page 37: Eternal static (RIT 2011)

Сборка пакетов – Processing– Стадия «generate»• Генерация новых файлов, на основе checkout’а• img2css – набор иконок в один CSS файл

– Стадия «preprocess»• Изменение содержимого файла, и/ли метаданных о нём• inline-includes – объединение файлов

– CSS: раскрытие @import– JavaScript: раскрытие _include_js()

Page 38: Eternal static (RIT 2011)

Сборка пакетов – Processing– Стадия «optimize»• Оптимизация формата файла, с сохранением

инварианта его семантики• yuicompressor – JS/CSS minification

– Стадия «produce»• Генерация других файлов на основе итоговых• gzip_static – создание сжатой версии статики

Page 39: Eternal static (RIT 2011)

Сборка пакетов – «вечная» статика• Конфигурация:

<handlername="eternal-static"process_path="/a/"target_path="/s/"match_ext="gif ico jpg png swf js css"expand_ext="js css"

/>

Page 40: Eternal static (RIT 2011)

Сборка пакетов – «вечная» статика• Сканируем директорию process_path на

предмет статических файлов с нужными расширениями

• Обрабатываем раскрываемые файлы (*.js *.css) на предмет ссылок на другие найденные ранее статические файлы

• Строим граф зависимостей

Page 41: Eternal static (RIT 2011)

Сборка пакетов – «вечная» статика• В директории target_path создаём соотв.

версии статических файлов (и их gzipped-версий, если у файлов был handler gzip_static)

• Итоговый файл будет называться filename_revision.ext, где revision – ревизия файла

/a/file.txt /s/file_REVISION.txt

Page 42: Eternal static (RIT 2011)

Сборка пакетов – «вечная» статика• Для статического файла, который не имеет

зависимостей (в т.ч. тех, которые не раскрываются вообще, типа картинок), ревизия равна mtime– VCS ревизия может быть недоступна, если файл

генерировался.– При генерации файлов mtime финального файла

всегда равен максимальному mtime его исходных файлов

Page 43: Eternal static (RIT 2011)

Сборка пакетов – «вечная» статика• Для статического файла, который имеет

зависимости, ревизия вычисляется как md5( join('\0', mtime, sort @eternal_static_deps) ) - т.е. создаётся семантически уникальная ревизия файла.– Жёсткое создание ревизии (md5 от тела файла) не

используется, чтобы при изменениях контента, которые семантически инвариантны (например, применён новый алгоритм оптимизации/obfuscation файлов) не создавалась новая ревизия.

Page 44: Eternal static (RIT 2011)

Сборка пакетов – «вечная» статика• Создаём файл /s/.mapping, который содержит

строки с парами "статический файл", "вечно-статический файл":/a/js/base.js /s/js/base_iv6uTQ.js

/s/css/main.css /s/css/main_msy5mT8H-Ak6hBAsce-30w.css

Page 45: Eternal static (RIT 2011)

Пример: 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>

Page 46: Eternal static (RIT 2011)

Установка пакетов• Файлы ставятся в share/htdocs/frontend• На этапе POST-INSTALL запускаем:

rsync -rlptgoD --checksum --delete-after share/htdocs/frontend htdocs/frontend– Это делается для того, чтобы при удалении пакета

в htdocs/frontend что-то оставалось

Page 47: Eternal static (RIT 2011)

Установка пакетов• Также копируем вечную статику:

rsync -rlptgoD --checksum htdocs/frontend/s/ htdocs/eternal– В htdocs/eternal файлы никогда не удаляются!

Page 48: Eternal static (RIT 2011)

Установка пакетов

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

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

Page 49: Eternal static (RIT 2011)

Конфигурация frontend’а

• Пример для обычного веб-сервера:location ^~ /s/ { alias htdocs/eternal;

gzip_static on; expires max;}

Page 50: Eternal static (RIT 2011)

Соглашения• Соглашения для раскрываемых файлов:

– Полное указание пути на ссылаемые файлы– В JS не использовать составление URL из частей ,

прописывать в коде полностью (как hash)

Page 51: Eternal static (RIT 2011)

favicon• IE (и иные браузеры) всегда запрашивают /favicon.ico, если нет <link rel=”icon” …/>

• Выдавать 404 – не выход, поскольку запросы всё равно будут идти

• Правильно так:location = /favicon.ico { root /path/to/htdocs; expires 30d;}

Page 52: Eternal static (RIT 2011)

52

IV. Tips & tricksIV. Tips & tricks

Page 53: Eternal static (RIT 2011)

Битва за байты: заголовки• Заголовок Server:

– Вообще-то его надо оставлять – это полезная статистикаhttps://www.openstat.ru/counter/trends/

– Но надо убирать из него длинных список скомпилированных модулей:Server: Apache/1.3.27 (Unix) mru_xml/0.471 gorgona/2.1 mod_jk/1.2.4 mod_ruby/1.0.7 Ruby/1.6.8 mod_mrim/0.17

– Также убирать прочие «гордые» заголовки:X-Powered-By: PHP/5.2.6-1+lenny9

Page 54: Eternal static (RIT 2011)

Битва за байты: HTML5 vs. XHTML<!DOCTYPE html> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML

1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<meta charset="utf-8"> <meta http-equiv="content-type" content="text/html; charset=utf-8">

<style> <style type="text/css">

<script> <script type="text/javascript">

Page 55: Eternal static (RIT 2011)

Используем TLS/SSL• TLS/SSL – уже не дорого в плане вычислений (CPU)

– Отдельные аппаратные акселераторы уже не нужны– CPU Intel Core i5+ поддерживают AES instruction set

• Privacy & confidentiality – всегда популярно среди параноиков– https://gmail.com, https://encrypted.google.com

• Цена сертификата Thawte - всего $45

Page 56: Eternal static (RIT 2011)

Минусы TLS/SSL• Дополнительные 4+ IP пакета на handshake (размер

public key имеет значение!)• Больший размер ответов

– record header, padding (если block cipher)– При тщательно подобранном размере ответа ресурса

(чтобы, скажем, влез в 1 IP пакет),применение SSL может повлечь +1 IP пакет

Page 57: Eternal static (RIT 2011)

Минусы TLS/SSL

• Блокирование на OCSP (проверка сертификата сервера) = +N*100ms– FF3+; IE* on Vista / Win7, …– Решение - OCSP stapling

• Не работает с chained certs• +~1KB данных (OCSP ответ)• Есть в Apache, нет в nginx

Page 58: Eternal static (RIT 2011)

Минусы TLS/SSL• SSL + IE6/7 + data:uri в HTML = «небезопасный

ресурс»– Доля IE6 + IE7 в Рунете - 9%

• SSL + отдача статики параллельно с нескольких хостов = дополнительные затраты на сертификаты– либо несколько сертификатов для разных хостов

(www.foobar.ru, img.foobar.ru)– либо условно дорогой wildcard (*.foobar.ru)

Page 60: Eternal static (RIT 2011)