eternal static (rit 2011)

Post on 13-Dec-2014

461 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

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

TRANSCRIPT

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

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

2011-04-26

3

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

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

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

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

ответов

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

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

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

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

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

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

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

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

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

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

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

– см. Stoyan Stefanov (Yahoo)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

• Closure compiler , YUI Compressor

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

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

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

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

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

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

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

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

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

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

Итого

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

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

18

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

md5( timestamp + @versioned_dependencies_urls)

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

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

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

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

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

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

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

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

20071%301

1%

3022%

30422%

4043%

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%

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

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

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

33

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

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

htdocs/ frontend/ eternal/ backend/

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

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

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

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

1. Checkout2. Processing

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

3. Packing distfiles

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

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

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

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

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

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

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

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

/>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

gzip_static on; expires max;}

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

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

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

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

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

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

52

IV. Tips & tricksIV. Tips & tricks

Битва за байты: заголовки• Заголовок 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

Битва за байты: 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">

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

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

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

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

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

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

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

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

Минусы TLS/SSL

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

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

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

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

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

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

top related