Ответ
Кеширование — это стратегия хранения копии данных или результатов вычислений во временном, быстром хранилище (кеше) для последующего быстрого доступа, что позволяет избежать повторного выполнения дорогостоящих операций (запросов к БД, сложных вычислений, внешних API-вызовов).
Основные уровни и типы кеширования в веб-приложении:
-
Кеширование на стороне клиента (браузер):
- HTTP-кеширование: Использование заголовков
Cache-Control,ETag,Last-Modifiedдля кеширования статических ресурсов (CSS, JS, изображения) и даже динамических ответов API. - LocalStorage / SessionStorage: Для хранения данных приложения на стороне клиента.
- HTTP-кеширование: Использование заголовков
-
Кеширование на стороне сервера (Server-side):
- Кеш приложения (In-memory): Хранение данных в оперативной памяти процесса (например, PHP-массив,
apcu_store()). Быстро, но не разделяется между процессами/серверами. - Распределённый кеш (Distributed Cache): Использование таких систем, как Redis или Memcached. Данные хранятся в отдельном сервисе, доступном всем экземплярам приложения. Это решает проблемы масштабирования и разделения кеша.
- Кеширование базы данных: Встроенные механизмы СУБД (например, кеш запросов в MySQL).
- Опкод-кеш (OPcache): Для скомпилированного PHP-байткода, ускоряет выполнение скриптов.
- Кеш приложения (In-memory): Хранение данных в оперативной памяти процесса (например, PHP-массив,
-
Прокси-кеширование и CDN:
- Varnish, Nginx cache: Кеширование целых HTML-страниц перед веб-сервером.
- CDN (Cloudflare, AWS CloudFront): Доставка статического и динамического контента с географически близких серверов.
Пример реализации кеширования результатов тяжёлого запроса с использованием Redis в PHP:
function getTopProducts(int $categoryId, int $limit = 10): array {
$redis = new Redis();
$redis->connect('redis-host', 6379);
$cacheKey = "top_products:cat_{$categoryId}:limit_{$limit}";
$ttl = 300; // Время жизни кеша — 5 минут
// Попытка получить данные из кеша
$cachedData = $redis->get($cacheKey);
if ($cachedData !== false) {
return json_decode($cachedData, true); // Возвращаем из кеша
}
// Данных в кеше нет — выполняем дорогой запрос к БД
$db = new PDO('mysql:host=localhost;dbname=shop', 'user', 'pass');
$stmt = $db->prepare("SELECT * FROM products WHERE category_id = ? ORDER BY sales DESC LIMIT ?");
$stmt->execute([$categoryId, $limit]);
$products = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Сохраняем результат в Redis перед возвратом
$redis->setex($cacheKey, $ttl, json_encode($products));
return $products;
}
Критические аспекты:
- Инвалидация кеша: Определение стратегии обновления кеша при изменении данных (TTL, ручная очистка, cache tagging).
- Сквозное кеширование (Cache-Aside / Lazy Loading): Паттерн, использованный в примере выше — приложение сначала проверяет кеш, и только при промахе загружает данные из источника.
- Согласованность данных: Кеш может содержать устаревшие (stale) данные, что необходимо учитывать в бизнес-логике.