Download - 2013 09 19 кеширование на клиенте и сервере
Евгений Дорошенко
Кеширование
H. Jackson Brown, Jr.
You can't hire someone to practice for you.
Практика
3
// returns factorial of n!function getFactorial(n) {!!if (0 === n) {!! !return 1;!!}!!return n * getFactorial(n - 1);!}!!var f1 = getFactorial(100); // 101 calls!var f2 = getFactorial(110); // 111 calls!var f3 = getFactorial(90); // 91 calls!
Расчёт факториала
4
var cacheFactorial = [];!!function getFactorial(n) {!!if (undefined !== cacheFactorial[n])!! !return cacheFactorial[n];!
!!if (0 === n)!! !cacheFactorial[n] = 1;!!else!! !cacheFactorial[n] = n * getFactorial(n - 1);!
!!return cacheFactorial[n];!
}!!var f1 = getFactorial(100); // 101 calls!var f2 = getFactorial(110); // 11 calls!var f3 = getFactorial(90); // 1 call!
Расчёт факториала с кешированием
5
Основная идея
• Получив данные, сохраняем их в кеш • При повторном обращении берём их из кеша
• Из кеша взять дешевле, чем расcчитать или скачать
6
Кеш должен быть быстрым, иначе он не нужен
Albert Einstein
In theory, theory and practice are the same. In practice, they are not.
Теория
Интерфейс кеша
Подобно ассоциативному массиву • Сохранить данные по ключу • Получить данные по ключу • Удалить данные по ключу
Хеш-таблица
• Хранит пары ключ-значение • Поддерживает операции - Вставка новой пары - Поиск значения по ключ - Удаление значения по ключу
Хеш-таблица. Как устроено
• Содержит массив H • Сначала получает индекс
i = hash(key)!• По индексу находит пару
H[i]!• Совершает целевую операцию
преобразование произвольных данных в строку или число
Хеширование
function hash(data) { var hash = 0, l = data.length; for (var i = 0; i < l; i++) { hash += data[i].charCodeAt(0); } return hash; }
Значения хеш-функции от различных данных совпадают
Хеширование. Коллизия
hash('трос'); // 4353 hash('сорт'); // 4353 hash('торс'); // 4353 hash('рост'); // 4353
Хеш-таблица. Разрешение коллизий
• Метод цепочек • Метод открытой адресации • Усложняется структура данных • Усложняются алгоритмы операций • Влияет на производительность
Хеш-таблица. Переполнение
• Спросить разрешения увеличить лимит • Не записывать данные в кеш (например,
exception) • Вытеснить старые данные новыми
Хеш-таблица. Алгоритмическая сложность
Факторы: • сложность алгоритма хеширования • сложность механизма обработки переполнения
• сложность механизма разрешения коллизий
Можно пожертвовать надёжностью во имя производительности
Инвалидация кеша
• Полнота инвалидации • Избыточность инвалидации • Сложность механизма инвалидации
Всегда нужен компромисс
Инвалидация по времени
• При сохранении указываем срок валидности
• Берём данные из кеша, только если срок валидности не истёк
Инвалидация по событию
• Меняем данные • Узнаём об их изменении
• Удаляем их из кеша
Инвалидация по ключу
• Ключ зависит от данных • Меняются данные -> меняется ключ • Данные по старому ключу однажды вытеснятся
Freeze файлов
• Имя файла - хеш от содержимого • Файл кешируется «навеки» • Меняется имя файла -> меняется имя • Новый файл -> кешируется отдельно • Браузер перезапрашивает только реально изменённые файлы
Кеширование на сервере
Способы кеширования на сервере
• В памяти приложения – быстро – много места – энергозависимо
• На жёстком диске – много места – энергонезависимо – медленно
Готовые системы кеширования
Популярные системы • memcached • redis Особенности • Всё сделано за нас • Возможность кеширования по сети • Может быть медленнее, чем память приложения
Что нужно кешировать на сервере
• результаты сложных вычислений • результаты запросов к БД • срендеренные HTML-страницы • предобработанные ресурсы
Протокол HTTP
Кеширование на клиенте
Кеширование в протоколе HTTP
Браузер • получает с сервера файлы • умеет сохранять их в кеш • выбирает сценарий кеширования по заголовкам
HTTP заголовок
• Файл по HTTP передаётся в обёртке • В обёртке есть специальные поля – заголовки
• Заголовок может быть установлен – Web-сервером (в конфиге) – Серверным приложением (в коде)
Как запретить http-кеширование
• Ответ сервера содержит заголовок Cache-Control: no-store!!• В HTTP 1.0 Pragma: no-cache!!• Для обратной совместимости ! !Pragma: no-cache!! !Cache-Control: no-store!
Что не нужно кешировать
• Результаты модифицирующих ajax-запросов
• Картинки CAPTCHA • И всё остальное, что меняется часто и непредсказуемо
Как закешировать на время
• Ответ сервера содержит заголовок ! !Expires: Mon, 15 Sep 2014 09:10:24 GMT!
• Ответ сервера содержит заголовок ! !Cache-Control: max-age=3600!
или ! !Cache-Control: must-revalidate, max-age=3600!
Когда нужно кешировать на время
• Всегда, когда время изменения известно, или поддаётся прогнозу
Кеширование с валидацией по времени
Сервер: !Cache-Control: no-cache!!Last-Modified: Sun, 15 Sep 2013 09:41:30 GMT!!Браузер:
If-Modified-Since: Sun, 15 Sep 2013 09:41:30 GMT!!Сервер, если ресурс не изменился: !304 Not Modified!!Сервер, если ресурс изменился: !200 OK!!Cache-Control: no-cache!!Last-Modified: Mon, 16 Sep 2013 09:41:30 GMT!
Кеширование с валидацией по Etag
Сервер: !Cache-Control: no-cache!!Etag: kj347kuyrqfweh!!Браузер:
If-None-Match: kj347kuyrqfweh!!Сервер, если ресурс не изменился: !304 Not Modified!!Сервер, если ресурс изменился: !200 OK!!Cache-Control: no-cache!!Etag: aslid8f7qe2q3w!
Когда нужно кешировать с валидацией
• Кешировать хочется • Измениться может в любой момент Что кешировать • Стили • Скрипты • Всё, что угодно
Управление кешем прокси
• Proxy находится между браузером и сервером • Proxy тоже умеет кешировать Разрешить кеширование на стороне прокси !Cache-control: public!
Разрешить кеширование только на стороне браузера !Cache-control: private!
3 факта о http-кешировании
• При заполнении кеша старые файлы вытесняются новыми
• Пользователь может очистить кеш • Управлять http-кешем из js нельзя
Application cache (offline web apps)
Кеширование на клиенте
Offline web applications
• HTML5 API • Позволяет web-приложению работать
offline • Позволяет предзагружать ресурсы в фоне
• Работать с кешем из javascript • В добрых браузерах поддерживается давно
• В ie – начиная с 10 версии
Offline web applications. Кратко об API
window.applicationCache.addEventListener( 'updateready', function() { // updating } );
<html manifest="example.appcache"> ... </html>
CACHE MANIFEST # Version 1.2.0 # Комментарий http://www.example.com/index.html http://www.example.com/header.png
Offline web applications. Как работает 1. Браузер впервые пришёл на страницу c manifest
• Загружает страницу • Загружает все ресурсы из manifest • Сохраняет всё в кеш
2. Браузер повторно пришёл на страницу c manifest
• Берёт все ресурсы из кеша • Запрашивает с сервера файл manifest • На applicationCache вызывает событие checking!
3. Если .manifest не изменился
• На applicationCache вызывает событие noupdate
!
Offline web applications. Как работает 4. Если .manifest изменился
• Перезапрашивает ресурсы по обычным правилам http-кеширования
• На applicationCache на каждый файл вызывает событие progress и error в случае ошибки
5. По завершении загрузки • На applicationCache вызывает событие cached!• Страницу сам не перезагружает
Offline web applications. Файл .manifest CACHE MANIFEST # version 1.0.2 CACHE: index.html style.css image1.png # Use from network if available NETWORK: network.html # Fallback content FALLBACK: / fallback.html
Offline web applications. JS API
• status - статус app cache • length - количество динамических записей
• item(index) - возвращает динамическую запись по индексу
• add(uri) - добавляет динамическую запись • remove(uri) - удаляет динамическую запись
• update() - раучной запуск обновления appCache • swapCache() - применить обновлённый кеш
В памяти js-приложения
Кеширование на клиенте
1. Результаты запросов к DOM-дереву
Кешируем в памяти js-приложения
var element = $('.myElement'); element.on('click', function() { // сотворить добро }); if (element.is(':visible')) { element.addClass('highlighted'); } else { element.removeClass('highlighted'); }
2. Результаты вызова «опасных методов»
Кешируем в памяти js-приложения
var height = $('.myElement’).height(); var width = $('.myElement’).width(); var offset = $('.myElement’).offset();
«Опасные» свойства • offsetHeight !• offsetWidth!
3. Длинные цепочки доступа
Кешируем в памяти js-приложения
document.forms[0].elements[0].value
• 3 операции доступа к полю объекта • 2 операции доступа к элементу массива
var value = document.forms[0].elements[0].value;
4. Свойство length массивов
Кешируем в памяти js-приложения
var l = items.length; for (var i = 0; i < l; i++) { // сотворить добро }
5. Результаты сложных вычислений
В cookies
Кеширование на клиенте
Кеширование в cookies
• cookies – фрагмент данных, хранимый на клиенте
• ограничение порядка 4kB • данные гоняются между клиентом и сервером
Web Storage
Кеширование на клиенте
Web Storage
• Позволяет хранить данные на клиенте • Поддерживается везде, кроме IE7 и старше • Данные хранятся на диске • Отдельно для каждого домена 2 уровня • Внутри – хеш-таблица • Не использует вытеснение
Web Storage. Ограничения
• Пространство на 1 домен 2-го уровня • IE: 10 MB • Firefox, Opera, Safari, Chrome: 5 MB • Chrome: фактически 2.5 MB
• В Opera и Firefox можно увеличить в настройках
55
window.localStorage!window.sessionStorage!
Web Storage. JS API
• length - количество элементов в storage • key(Number index) - возвращает ключ n-го элемента • getItem(key) - возвращает значение по ключу • setItem(key, data) - сохраняет значение по ключу • removeItem(key) - удаляет пару ключ-значение • clear() - очищает storage
• Событие storage на window!
Web Storage. Переполнение
• Opera предлагает увеличить предел • Другие браузеры бросают exception
QUOTA_EXCEEDED_ERR
Web Storage. Для чего?
• Сохранение значений форм • Хранение ресурсов, загруженных ajax-ом
• Взаимодействие между соседними вкладками
Web Storage. Недостатки
• Неструктурированные данные • Может работать медленно
IndexedDB и WebSQL
Кеширование на клиенте
IndexedDB и WebSQL
• больше данных (десятки мегабайт) • структурировано, индексируется • может быть быстрее, чем Web Storage
• сложный API • webSQL не поддерживается в IE и FF • indexedDB не поддерживается в Safari
Заключение
Заключение
• Кеширование – общепринятый паттерн • Кеширование ускоряет • Платим памятью и сложной логикой • Данные однажды устареют • Помним о браузерном кешировании • Кешировать в память приложения – дёшево и эффективно