Кэш ответов
Кэширование целых HTTP-ответов. По умолчанию выключено, включается двумя настройками.
| Настройка | По умолчанию | |
|---|---|---|
pageblocks_http_cache | выкл | Включает |
pageblocks_http_cache_ttl | 3600 | Время жизни в секундах |
Это не то же самое, что сервис Cache, который хранит значения, которые вы туда сами положили. Здесь хранятся отрендеренные страницы, и происходит это автоматически.
Что кэшируется
Только ответ, у которого выполняется всё три:
- запрос
GET, - от анонимного посетителя — не авторизован ни в текущем контексте, ни в
mgr, - ответ 200.
Всё остальное проходит мимо: формы, менеджер, страница залогиненного пользователя, 404.
Почему только анонимные
Закэшированная страница общая для всех, кто попросит этот адрес. Один авторизованный ответ в таком хранилище — и следующий посетитель получит чужое приветствие. Правило узкое намеренно, и расширить его настройкой нельзя: цена ошибки — отдать данные одного пользователя другому.
Ключ
Ключ — это контекст, плюс хэш адреса запроса, плюс отпечаток гостевого состояния посетителя. Строка запроса входит в адрес, поэтому /catalog?page=2 и /catalog?page=3 — разные записи.
Отпечаток — это GuestCookies::fingerprint(), md5 от значений зарегистрированных гостевых cookie, пришедших с запросом. Отсюда три следствия:
- у двух гостей ключи разные, и запись одного другому не достанется;
- у одного и того же гостя ключ один, то есть кэш ему наконец работает;
- у посетителя без гостевых cookie ключ прежний, байт в байт. Таких большинство — они делят одну запись, а не получают свою; заодно уже накопленный кэш после обновления остаётся годным.
Гостевая cookie должна быть зарегистрирована
В отпечаток попадают только имена, переданные в GuestCookies::register(). Незарегистрированная cookie с гостевым состоянием означает, что кэш не отличит одного гостя от другого — ровно та утечка, против которой всё и сделано. См. Гости.
Отпечаток считается один раз за запрос и запоминается. Ключ спрашивают дважды — на чтении в маршрутизации и на записи при отдаче ответа, — и токен, выданный между ними, иначе сохранил бы ответ под ключом, в который никто не смотрел.
Инвалидация происходит сама
Сохранение модели сбрасывает весь кэш ответов. Не нужно размечать страницы тегами, вычислять, каких адресов коснулась правка, и дописывать хук при добавлении таблицы.
Исключение — модель, которая объявила, что её сохранение не меняет ничего видимого посетителю: protected bool $flushesResponseCache = false; на ней отменяет сброс. Это про служебные таблицы — так отказался журнал почты: рассылка из трёхсот писем иначе чистила бы хранилище шестьсот раз подряд и превращала кэш в измеримое замедление. У всего, что хранит конструктор, значение по умолчанию — true.
Это намеренно грубо. Точная инвалидация — то место, где кэши ответов и ломаются: страницу, которая не обновилась, отлаживать заметно дороже, чем пережить повторное наполнение кэша. На сайте, где контент меняется пару раз в час, это ничего не стоит; на сайте, где что-то пишет в базу на каждом запросе, кэш не удержит ничего — и это признак, что фича такому сайту не подходит, а не повод усложнять правило.
Восстановление резервной копии тоже сбрасывает кэш.
Неудачный сброс проглатывается намеренно: проблема с кэшем не должна ломать сохранение модели или запрос.
Где это стоит
Поиск в кэше происходит в маршрутизации, до передачи запроса дальше: попадание стоит одного чтения и до контроллера не доходит. Запись — при отправке ответа и только для 200.
Записи живут в кэше MODX под pageblocks/http, поэтому очистка кэша сайта их убирает.
Когда включать
Имеет смысл для сайта, который в основном анонимно читают: каталог, блог, лендинг под нагрузкой. Магазин сюда тоже входит: гость с корзиной кэшируется под своим ключом, так что каталог отдаётся из хранилища, а корзина остаётся личной.
Бесполезно для личного кабинета и всего, где посетитель залогинен: такие запросы не кэшируются никогда, а проверка стоит немного на каждом.
Убедитесь, что он вообще работает
Включение ничего не меняет внешне, поэтому легко решить, что стало лучше. Измерьте: загрузите страницу гостем дважды и сравните время. Если вторая загрузка не быстрее, ничего не кэшируется — скорее всего, что-то пишет в базу на каждом запросе и тут же сбрасывает хранилище.