Стратегии кэширования веб-приложений
Зачем нужна стратегия кэширования
Кэширование — самый мощный инструмент оптимизации производительности. Правильная стратегия кэширования может снизить нагрузку на сервер на 90%, уменьшить время отклика в 10-100 раз и значительно сэкономить на инфраструктуре. Но кэширование без стратегии приводит к устаревшим данным, багам и сложной отладке.
Уровни кэширования
1. Браузерный кэш (клиентский)
Самый близкий к пользователю уровень. Управляется проверку HTTP-заголовков Cache-Control, ETag, Expires. Нулевая задержка при попадании в кэш — ресурс загружается с диска.
Подходит для: статических ресурсов (CSS, JS, изображения, шрифты), редко меняющихся страниц.
2. Service Worker / Application Cache
Программируемый кэш в браузере. Service Worker перехватывает сетевые запросы и может обслуживать их из кэша, даже офлайн. Даёт полный контроль над стратегией кэширования на клиенте.
Подходит для: PWA, офлайн-функциональности, кэширования API документацию-ответов.
3. CDN (Content Delivery Network)
Распределённая сеть серверов, кэширующая контент ближе к пользователям. Снижает latency и разгружает origin-сервер. Управляется заголовками Cache-Control, s-maxage, Surrogate-Control.
Подходит для: статических ресурсов, API с публичными данными, HTML-страниц.
4. Reverse Proxy (Varnish, nginx)
Кэширующий прокси перед application-сервером. Обслуживает запросы из кэша без обращения к приложению. Varnish может обрабатывать десятки тысяч запросов в секунду.
Подходит для: HTML-страниц, API-ответов, снижения нагрузки на application-сервер.
5. Серверный кэш приложения
In-memory кэш (Redis, Memcached) внутри приложения. Кэширует результаты вычислений, сериализованные объекты, результаты API-вызовов к внешним сервисам.
Подходит для: результатов сложных запросов, ответов внешних API, сессий, конфигурации.
6. Кэш базы данных
Встроенный кэш СУБД (InnoDB buffer pool, query cache). Кэширует данные и индексы в памяти. Управляется конфигурацией БД, не требует изменений в коде.
Подходит для: часто читаемых данных, повторяющихся запросов.
Стратегии кэширования
Cache-Aside (Lazy Loading)
Приложение проверяет кэш. Если данных нет (cache miss), загружает из БД и помещает в кэш. Самый распространённый паттерн.
function getUser(int $id): array {
$key = "user:{$id}";
$cached = cacheGet($key);
if ($cached !== null) {
return $cached; // cache hit
}
$user = db_query("SELECT * FROM users WHERE id = ?", [$id]);
cacheSet($key, $user, 3600); // TTL: 1 час
return $user;
}
Плюсы: простота, данные кэшируются по мере необходимости.
Минусы: первый запрос всегда медленный, возможна устаревшая информация до истечения TTL.
Write-Through
При записи данные обновляются одновременно в кэше и в БД. Кэш всегда актуален.
Плюсы: данные всегда свежие, нет cache miss на чтение.
Минусы: замедляет запись, кэшируются все данные (даже те, которые не читаются).
Write-Behind (Write-Back)
Данные сначала записываются в кэш, а в БД — асинхронно с задержкой. Максимальная скорость записи.
Плюсы: быстрая запись, снижение нагрузки на БД.
Минусы: риск потери данных при сбое кэша, сложность реализации.
Read-Through
Кэш сам загружает данные из БД при cache miss. Приложение обращается только к кэшу.
Плюсы: простой код приложения.
Минусы: кэш должен знать о источнике данных.
Инвалидация кэша
«В информатике есть только две трудные задачи: инвалидация кэша и именование вещей» — Фил Карлтон.
Time-based (TTL)
Кэш автоматически устаревает после заданного времени. Простейший подход, но данные могут быть устаревшими до истечения TTL.
Event-based
Кэш инвалидируется при изменении данных. Более сложный, но обеспечивает актуальность.
function updateUser(int $id, array $data): void {
db_query("UPDATE users SET ... WHERE id = ?", [...$data, $id]);
cacheDel("user:{$id}"); // Инвалидация кэша
}
Версионирование
Для статических ресурсов: имя файла содержит хеш содержимого (app.a1b2c3.css). Изменение содержимого = новый URL = автоматическая инвалидация.
Purge API
CDN и прокси обычно предоставляют API для принудительной очистки кэша. Используйте при срочных обновлениях.
Типичные ошибки
- Кэширование без TTL — данные могут устареть навсегда
- Слишком короткий TTL — кэш не успевает приносить пользу
- Кэширование персональных данных в shared-кэше — утечка данных между пользователями
- Cache stampede — при истечении популярного кэша сотни запросов одновременно идут в БД. Решение: mutex lock или stale-while-revalidate
- Отсутствие мониторинг сайтов — без метрик hit/miss ratio невозможно оценить эффективность кэша
Мониторинг эффективности
Используйте тест скорости Enterno.io для оценки влияния кэширования на время загрузки. Проверьте заголовки HTTP-ответа для контроля настроек Cache-Control на вашем сайте.
Итоги
Эффективная стратегия кэширования использует несколько уровней: браузер для статики, CDN для глобальной доставки, Redis для данных приложения. Выбирайте паттерн (Cache-Aside для большинства случаев) и продумайте инвалидацию. Мониторьте hit/miss ratio и настраивайте TTL на основе данных.
Проверьте ваш сайт прямо сейчас
Проверить →