Кэширование в веб-приложениях — что, где, когда

JetSnail.svg

Виталий Филиппов

Кто я?

Vitalif.jpg

В CUSTIS — ведущий веб-разработчик

Мои доклады и контакты: http://yourcmc.ru/wiki/User:VitaliyFilippov

Поддерживаю сборку MediaWiki-notext.svg MediaWiki4Intranet: http://wiki.4intra.net/ Wiki4intranet-logo.svg

(«И давно вы страдаете программизмом?»)

  • Кодинг лет с 11 :)
  • Linux’оид ± веб-разработчик то ли с 16, то ли с 17, [сайтиков понаписал]
  • Языки: в основном PHP, Perl, Python
  • Win&Mac must die! Only GPL! Only Free Software! Only hardcore :)

Адрес этого доклада: http://lib.custis.ru/WebAppCaching

О чём доклад?!

  • Веб-приложения
  • Кэширование
    • Где? Внешний кэш vs память процесса
    • Как надо? Инвалидация
    • Оценка эффективности
    • Как НЕ надо? Фейлы
  • Client-side кэширование (HTTP)
  • Приёмы server-side кэширования
  • Дополнительные меры

Веб-приложения

Clouds.svg

Веб-приложение ≈ примерно САЙТ!

  • Сетевое, клиент-серверное
  • Открытые стандарты, протокол HTTP

На клиенте (клиент = браузер):

  • Основное: HTML+CSS+JavaScript

На сервере:

  • Очень популярен LAMP
  • Разное

LAMP.svg

Схема веб-приложения

Webapp-nocache.svg

Кэши есть везде!

Webapp-withcache.svg

Кэширование

JetSnail-grayed.svg

Кэширование

Обмен вычислений на память!

ScaleCpuRam.png

То есть, сохранение и повторное использование чего-нибудь

Кэшировать можно почти всё, что угодно — данные, код, соединения, адреса…

Кэш vs БД

База заранее вычисленных данных — не кэш! Ибо:

  • Кэш обычно строится на лету, динамически.
  • Записи в кэше обычно непостоянны.
    (с этим связан Fail №1 — использование кэша как БД)
  • Обычно есть вытеснение
    LRU / FIFO / прочие[1]
Например, memcached — кэш, а Redis — БД.
  1. Алгоритмы кэширования — http://en.wikipedia.org/wiki/Cache_algorithms

Где кэшировать данные?

Where to cache.svg
  • Внешний кэш + сериализация
    PHP — без вариантов, только внешний
  • Память процесса
    Управляемая? Неуправляемая?
  • Распределённый кэш

Память процесса

GC1.png

Больше проблем, чем плюсов ☹. Самая главная:

Такой кэш не масштабируется!

Управляемая память:

☺ Накладные расходы = 0, объект живой
☹ Живые объекты — толстые
☹ Может прийти GC

Неуправляемая/разделяемая (например, так делают Одноклассники)

☹ Те же накладные расходы на сериализацию

Внешний кэш

Cat shared cache.jpg

Просто и популярно — memcached ± redis

☺ Может быть разделяемый, распределённый

☹ Накладные расходы на сериализацию и сеть

Локально используйте UNIX сокеты
PHP: ставьте igbinary
Java, C++, Python: protobuf от google

Consistent hashing

Для быстрого добавления/удаления узлов

ConsistentHashing.png

OkayFace.svg

А если данные меняются?

Инвалидация кэша

⇒ Кэш нужно обновлять (сбрасывать).

Простейшие варианты:

  • Не сбрасывать вообще (только добавление)
  • Сбрасывать по ключу (если нет зависимостей)
  • Сбрасывать ВСЁ (если меняется всё 1 раз в день)

Инвалидация

А если у объектов сложные зависимости?

BigGraph.jpg

По времени (TTL)

TTL.jpg

☺ Просто, но не оперативно ☹

  • Удаление через заданное время жизни (TTL)
  • TTL без поддержки TTL: при чтении сверять срок годности
  • Микрокэширование: TTL = 1 секунда

Наиболее гибко — По тегам

TagCloud.png
  • Тег = зависимость
  • На элементы кэша ставятся теги
  • Сброс всех ключей по тегу = обновление зависимости
  • Иерархия: если тег сам зависит от других

Теги без поддержки тегов

Списочный метод:

  • Хранить списки ключей для каждого тега
  • Медленный сброс

Версионный метод :

  • Сброс = инкремент версии тега
  • При чтении сверяем версию

Но: нужен Redis!

Оценка эффективности кэша

AraGlushak.jpg

Главное — ВЫИГРЫШ В ПРОИЗВОДИТЕЛЬНОСТИ

  • Профилирование С кэшем и БЕЗ кэша
  • Hit/Miss (попадания/промахи)
    Низкие hit: горячие/взрыв/дублирование/размер
  • Размер кэша, количество вытеснений

Типичные фейлы

(Анти-паттерны кэширования)

Слишком мало Слишком много
Пустая миска.jpg Тоша объелся.jpg

Fail № 1

«Положил и точно заберу»

Например, сессии в memcached

Fail № 2

Кэширование авторизованных страниц

Или одного и того же списка с выбранным элементом

(итог — комбинаторный взрыв)

Fail № 3

Аппарат искусственного дыхания

Будет очень грустно его отключать (сбрасывать кэш)

Fail № 4

Cache hit под 100 %, а всё тормозит!

Кэшировали яро, но не то, что надо

Заключеньице

  • Кэш — не БД!
  • Обычно внешний кэш лучше (масштабируется)
  • Обычно полезны теги
  • Всегда нужна оценка работы кэша

Клиентское кэширование

Http.jpg

HTTP

  • Простой текстовый протокол
  • Почти Stateless (почти REST)
  • Keepalive — кэш соединений
Запрос Ответ

МЕТОД /адрес/?параметры HTTP/1.1
Host: домен.сайта
Заголовок: Значение

Тело запроса (при загрузке файлов)

HTTP/1.1 000=код_статуса Статус Ответа
Content-Type: text/html; charset=UTF-8
Заголовок: Значение

Тело запроса (текст страницы)

Блин! Что ещё за кэш?

google://php отключить кэш

  • Как отключить кэширование на PHP — Создание и Продвижение Сайтов
  • Запрет кэширования посредством PHP — Справочник веб-языков
  • Записки программиста PHP — Как отключить кэширование страниц
  • 100%-ное отключение кэширования — Форум програмистов
  • How to Remove Cache in PHP | eHow

Пацаны, у меня фаервол

VeryNewAlgo.jpg
ChallengeAccepted.svg

Cache-Control: no-cache, no-store, must-revalidate, max-age=0 Pragma: no-cache Vary: * Expires: Thu, 01 Jan 1970 00:00:00 GMT

GodKillsKitten.jpg

HTTP-кэш любят все

  • браузеры — быстрее открывают страницу (повторно, «Назад»)
  • поисковики — быстрее индексируют
  • прокси — лучше работают
  • А нагрузка — снижается…
    Защита от умника с кнопкой F5

HTTP-кэш

Прокси-сервер…
  • Браузеры/прокси могут сохранять HTTP-ответы
  • Есть статус ответа HTTP 304 Not Modified
  • Есть заголовки для управления кэшированием
    Причём частично в довольно диких комбинациях
  • Куча костылей для проксей

HTTP-кэш: схема

HTTP Caches.svg

Управление HTTP-кэшированием

HTTP 1.0: (по времени)

  • Last-Modified, If-Modified-Since
  • Expires, Pragma: no-cache

HTTP 1.1: (по времени и значениям)

  • ETag, If-None-Match
  • Vary
  • Cache-Control

Cache-Control

  • no-cache (запрет кэширования)
  • must-revalidate (костыль)
  • private, public (личное/публичное)
  • срок кэширования: max-age, s-maxage (для прокси)
    Warning icon.svg (осторожно!)

В Cache-Control…

WAT Owl.jpg

…Есть странные опции

Странные опции

  • no-transform
    OperaTurbo.png
  • no-store (отвернись и не смотри)
  • proxy-revalidate, community=…
  • в запросе: max-age, only-if-cached, min-fresh, max-stale

Long Poll

Kotiki.jpg

(как пример кэша соединений)

Задача: твиттер/вконтактик, показывать новых котиков в реальном времени.

При ожидании ответа сервер подвешивает соединение клиента на N секунд.

Заключение

Для содержимого достаточно отслеживать даты изменений:

  • no-cache + Last-Modified: ...
  • 304 Not Modified + Date: ...

Для статики:

  • Большой max-age

Кэш приложения

Gepard.jpg

(основное, на что мы можем повлиять!)

Что кэшировать?

Как можно бОльшие куски информации:

страницы (если можно; обычно — нельзя)
→ блоки (побить на них всю страницу; обычно — можно)
→ выборки (только тяжёлые)
→ объекты (только очень тяжёлые)

Приёмы

Что делать с макаронами? [плохим кодом]

UdarNogoi.svg

MVC

Нет понятия «объект»? ⇒ Модель

Не можем кэшировать шаблоны, так как непонятно, где шаблоны? ⇒ View

Побочные эффекты?

⇒ Инкапсулировать их в Stash

Lambda-Walk по связанным объектам?

Либо M-V-Presenter

Либо массовая автозагрузка

Шаблон читает из БД…

…как кэшировать?

⇒ Кэшировать после шаблона

HMVC

HMVC.svg CachedSiteBlocks.svg

Иерархический MVC

  • Блочная структура естественна
  • Удобно кэшировать!
  • Юзают авторы поделия под названием Kohana Framework Thumbs down.svg
  • Однако они о кэшировании НЕ ЗНАЮТ! :D и поэтому его там правильного нет

На что ещё можно влиять

Веб — не низкий уровень, до кэша CPU не спустишься :)

  • Кэш ЯП — заюзать (PHP: APC/XCache, остальные: предзагрузка)
  • Правильный сериализатор — поставить
  • Кэш СУБД

JavaScript:

  • Поменьше фреймворков Thumbs down.svg
  • Писать ручками в прототипах :)
  • Обработчики inline

Кэш СУБД — примеры

MySQL:

  • Запросы: query-cache-limit, query-cache-size
  • Таблицы: table-open-cache, table-definition-cache
  • Дисковый: innodb-buffer-pool-size
  • Бинлог: binlog-cache-size
  • Потоки: thread-cache-size

PostgreSQL:

  • Дисковый: shared_buffers
  • Остальное (планы, таблицы): work_mem
  • Размер кэша ОС: effective_cache_size

Резюмируем

  • Стараться кэшировать целые страницы
  • HMVC
  • memcached, redis
  • Теги, Last-Modified
  • PHP: обязательны APC/XCache, igbinary
  • Тюнить кэш СУБД
  • Поменьше фреймворков, побольше разума

ThatsAllFolksCut.svg

http://lib.custis.ru/WebAppCaching

vfilippov d0g custis d0t ru
vitalif d0g mail d0t ru


Любые правки этой статьи будут перезаписаны при следующем сеансе репликации. Если у вас есть серьезное замечание по тексту статьи, запишите его в раздел «discussion».

Репликация: База Знаний «Заказных Информ Систем» → «Кэширование в веб-приложениях - что, где, когда»