Пошук уроків, статей та іншого контенту
Зберігання готового результату замість повторного обчислення — і найважча проблема кешування.
Кешування зберігає результат дорогої операції (складний запит до бази даних, виклик зовнішнього API, важке обчислення) і повертає збережений результат при повторному запиті тих самих даних — замість того, щоб виконувати ту саму дорогу роботу знову. Це один із найефективніших і найпоширеніших способів зменшити навантаження на нижчі шари системи.
На рівні клієнта/браузера — HTTP-кеш заголовків (стаття «REST vs GraphQL» згадує це в контексті кешованості REST-запитів).
На рівні CDN, ближче до користувача географічно (детальний окремий урок далі в цьому курсі).
На рівні застосунку — окреме сховище на кшталт Redis для готових результатів обчислень чи запитів.
На рівні бази даних — сама СУБД кешує часто використовувані дані й плани запитів у пам'яті внутрішньо.
1. Застосунок питає кеш: чи є готові дані?
2. Якщо є (cache hit) — повернути одразу, без звернення до бази даних.
3. Якщо немає (cache miss) — прочитати з бази даних, зберегти результат у кеш, повернути.Cache-aside — найпоширеніший патерн: застосунок сам вирішує, коли звертатись до кешу, а коли до основного джерела даних, і сам відповідає за заповнення кешу після cache miss.
«Є лише дві складні речі в інформатиці: інвалідація кешу та іменування речей» — відомий, напівжартівливий вислів, що влучно описує реальну складність: коли дані в основному джерелі змінюються, застарілий кеш продовжує повертати старе значення, доки його явно не інвалідувати (позначити застарілим і оновити чи видалити). Забута інвалідація — джерело одних із найважчих для діагностики багів: «дані в базі правильні, але застосунок усе одно показує старе значення».
Time-to-live (TTL) — простіша альтернатива ручній інвалідації: кожен закешований запис автоматично вважається застарілим і видаляється через заданий проміжок часу, незалежно від того, чи дані реально змінились. Простіше в реалізації, ціною того, що дані можуть бути застарілими протягом усього TTL, навіть якщо змінились відразу після кешування.
Кешування завжди означає компроміс між швидкістю (менше повторної роботи) і узгодженістю даних (ризик віддати застарілу версію) — це той самий компроміс, що й у Next.js кешуванні fetch-запитів (курс Next.js: у Next.js 15+ fetch за замовчуванням НЕ кешується саме через свідомий вибір на користь свіжості даних за замовчуванням, з явним opt-in для кешування там, де застарілість прийнятна).
Кешувати дані, що змінюються часто й де застарілість неприйнятна (баланс рахунку, наявність товару в момент оплати), без ретельно продуманої стратегії інвалідації.
Занадто довгий TTL «про всяк випадок» — дані лишаються застарілими довше, ніж прийнятно для конкретного випадку використання.
Забувати інвалідувати кеш після мутації даних (та сама проблема, що й revalidatePath у Server Actions Next.js) — застосунок оновлює базу даних, але користувач і далі бачить старе значення з кешу.
Кешування зберігає готовий результат дорогої операції для повторного використання, зменшуючи навантаження на нижчі шари системи, — найпоширеніший патерн, cache-aside, лишає застосунку відповідальність за заповнення кешу після cache miss. Інвалідація застарілих даних — найважча практична проблема кешування; TTL дає простішу, автоматичну, але менш точну альтернативу ручній інвалідації. Кешування завжди міняє швидкість на ризик тимчасово застарілих даних.