Cache-aside (ліниве кешування) - найпоширеніша стратегія: застосунок сам керує кешем.
- Шукаємо значення в кеші.
- Знайшли - повертаємо.
- Не знайшли - читаємо з бази, кладемо в кеш, повертаємо.
$stats = Cache::remember("dashboard:stats:{$teamId}", now()->plus(minutes: 10), function () use ($teamId) {
return Order::where('team_id', $teamId)->selectRaw('count(*) as total, sum(amount) as revenue')->first();
});
При зміні даних - інвалідувати кеш (видалити ключ), щоб наступне читання взяло свіжі дані:
Cache::forget("dashboard:stats:{$teamId}");
Інші стратегії:
- write-through - при записі в базу одночасно оновлюється кеш. Кеш завжди актуальний, але кожен запис дорожчий, а в кеш потрапляють і дані, які ніхто не читає;
- write-behind - запис спершу в кеш, у базу - пізніше пакетами. Швидко, але ризик втрати даних;
- read-through - кеш сам завантажує дані з бази (зазвичай у спеціалізованих системах).
Як обрати TTL (час життя):
- як довго застарілі дані прийнятні для бізнесу? Курс валют - хвилина, список категорій - година чи доба, статистика для дашборду - кілька хвилин;
- як часто змінюються дані і чи є надійна інвалідація при змінах. З інвалідацією TTL може бути довгим - він лише страховка;
- ціна обчислення: дороге обчислення варто кешувати довше;
- випадковий розкид (jitter) - щоб тисячі ключів, створених одночасно, не застаріли в одну мить і не вдарили по базі разом.
Що кешувати: дорогі обчислення й запити, що повторюються; дані, однакові для багатьох користувачів. Що не кешувати: дешеві запити за первинним ключем, дані, що мають бути абсолютно точними (баланс при оплаті).
Найскладніше в кешуванні - інвалідація: кожне місце, що змінює дані, має знати, які ключі скинути. Теги кешу (Cache::tags(['team:5'])->flush()) у Redis спрощують групову інвалідацію.