Первая версия кэша блоков была классической: версия данных в имени ключа. Изменилось что-то в каталоге — подняли версию, ключи стали новыми, старые больше никто не читает. Просто и правильно. Пока не посмотришь, сколько места занимают «больше никто не читает».
Это вторая часть цикла «Кэш фрагментов и Redis».
Версии в ключе: инвалидация бесплатна, мусор — нет
$key = 'frag_grid_' . get_option('catalog_ver') . '_' . md5(serialize($args));
Сброс — это одна запись: catalog_ver++. Но все ячейки с прошлой версией остаются в базе сиротами до истечения срока. На каталоге с обменом 1С версия поднималась постоянно, и сирот набегало до 3 ГБ в сутки. Срок жизни держали коротким — 3 дня, — чтобы мусор хоть как-то уходил. А короткий срок означал, что редкие комбинации успевали истечь и отдавались с MISS.
И главное: после сброса каждая ячейка — MISS. Посетитель ждёт рендер, потому что под новым ключом ничего нет.
Версии в значении: stale-while-revalidate
Ключ стал стабильным — только параметры блока, хост и тип устройства. А версии переехали внутрь значения:
// что лежит в ячейке
[
'html' => '…',
'_ver' => 'v812', // версия данных на момент рендера
'_code' => 1760000000, // версия кода: время изменения манифеста сборки
]
При чтении — три исхода:
| Условие | Статус | Что происходит |
|---|---|---|
_code не совпал | MISS | код сменился, старая разметка может не работать с новым скриптом — рендер сейчас |
_ver совпал | HIT | отдать как есть |
_ver не совпал | STALE | отдать старое мгновенно, поставить горячую задачу на пересборку |
function frag_get_or_render(string $type, array $args, callable $render): array {
$key = frag_key($type, $args);
$cell = frag_store_get($key);
if (!$cell || $cell['_code'] !== frag_code_version()) {
$cell = frag_render_and_store($key, $type, $args, $render); // MISS
header('X-Frag-Cache: MISS');
} elseif ($cell['_ver'] !== frag_data_version($type, $args)) {
frag_queue_hot($type, $args); // STALE
header('X-Frag-Cache: STALE');
} else {
header('X-Frag-Cache: HIT');
}
return $cell;
}
Версии по разделам
Одна версия на весь каталог — значит, смена цены в одной категории делает устаревшими блоки всех категорий. Версия у каждого раздела своя: изменилась цена в одной категории — устаревают блоки только этой категории и её родителей.
Срок жизни — неделя
При чтении «отдай старое» длинный срок безопасен: устаревшее обновится при первом же показе. А короткий срок, наоборот, вредит — редкие комбинации успевают исчезнуть и отдаются с MISS. Срок вырос с 3 до 7 дней.
Цена решения
После изменения данных одну-две минуты показывается прежний контент — пока воркер не пересоберёт ячейку. Для каталога это допустимо; для цены в корзине — нет, и такие вещи в кэш блоков не кладутся.
Как проверить весь цикл
- первый запрос — MISS;
- второй — HIT;
- поднять версию раздела — следующий запрос STALE (~0,3 с) и горячая задача в очереди;
- воркер отработал — снова HIT с новым содержимым.
Кэш блоков есть, а после каждого обмена всё медленное?
Пришлите адрес — проверю, как у вас устроена инвалидация блоков.
// загружаю комментарии…