Кеш — это не просто «быстрая память». То, как ваше приложение взаимодействует с кешем, определяет согласованность данных, сложность кода и отказоустойчивость. Выбор паттерна зависит от сценариев нагрузки.
1. Cache-Aside (Lazy Loading) — Самый популярный паттерн
Принцип: Приложение управляет кешем напрямую. Кеш не обращается к источнику данных сам.
Алгоритм для чтения (Read):
Приложение получает запрос на данные по ключу.
Проверяет кеш. Если данные есть (Cache Hit) — возвращает их.
Если данных нет (Cache Miss) — обращается к основной БД.
Получает данные из БД, записывает их в кеш и возвращает клиенту.
Алгоритм для записи (Write):
Приложение обновляет данные в основной БД.
Инвалидирует (удаляет) соответствующий ключ в кеше.
Плюсы:
Простота: Легко понять и реализовать.
Отказоустойчивость: Если кеш упал, приложение продолжает работать напрямую с БД (правда, с повышенной нагрузкой).
Кеш содержит только реально запрашиваемые данные. Нет мусора.
Минусы:
Cache Miss Penalty: При промахе клиент ждет трех операций: проверка кеша, чтение из БД, запись в кеш.
Проблема согласованности (Coherency): Между обновлением БД и инвалидацией кеша возможна небольшая временная окно, когда кеш вернет устаревшие данные (stale data). Это eventual consistency.
«Грязное чтение»: Если два параллельных потока обработают промах на одни данные, оба прочитают из БД и попытаются записать в кеш (решается блокировками или условной записью).
Где использовать: Универсально для большинства сервисов, особенно с непредсказуемым или разнообразным доступом к данным. Классика для кеширования объектов пользователя, каталогов товаров.
2. Read-Through — Более «умный» кеш
Принцип: Приложение считает кеш основным источником данных. Кеш знает, как загружать данные из БД при промахе.
Алгоритм для чтения:
Приложение всегда запрашивает данные только из кеша.
Если данные есть — кеш возвращает их.
Если данных нет — кеш сам загружает их из БД, сохраняет у себя и возвращает приложению.
Алгоритм для записи: Аналогичен Cache-Aside: приложение пишет в БД и инвалидирует кеш.
Плюсы:
Чище архитектура: Приложение не знает о БД, только о кеше.
Упрощение кода: Вся логика загрузки при промахе централизована в кеше (или его библиотеке).
Эффективнее при «прогретом» кеше: Уменьшает задержку для частых запросов.
Минусы:
Требует более сложной настройки кеша (или использования готовых решений, таких как распределенные кеши с этой функциональностью).
Первая загрузка (cold start) может быть болезненной: все запросы идут в БД, пока кеш не заполнится.
Где использовать: Идеально для read-heavy нагрузок с предсказуемыми ключами. Часто используется в комбинации с Write-Through/Write-Behind.
3. Write-Through — Кеш как «привратник» для записи
Принцип: Любая запись проходит сначала в кеш, а затем синхронно в БД. Кеш всегда актуален.
Алгоритм для записи:
Приложение записывает данные в кеш.
Кеш немедленно и синхронно записывает те же данные в БД.
Операция считается успешной, только когда завершились оба действия.
Алгоритм для чтения: Используется Read-Through (запрос только к кешу).
Плюсы:
Полная согласованность данных (Strong Consistency): Гарантия, что данные в кеше и БД идентичны.
Надежность: Данные не потеряются при сбое, так как сразу сохранены в постоянное хранилище.
Минусы:
Высокая задержка записи (Write Latency): Клиент ждет завершения записи в (относительно медленную) БД.
Риск перегрузки БД: Каждая операция обновления кеша создает нагрузку на БД.
Где использовать: Для данных, где консистентность критически важнее производительности записи. Пример: финансовые транзакции, системные конфигурации.
4. Write-Behind (Write-Back) — Максимум производительности записи
Принцип: Приложение пишет только в кеш. Кеш подтверждает операцию немедленно, а затем асинхронно, пачками (batch) обновляет БД.
Алгоритм для записи:
Приложение записывает данные в кеш.
Кеш немедленно подтверждает успех клиенту.
Через некоторое время (секунды, минуты) кеш пачкой скидывает накопленные изменения в БД.
Плюсы:
Очень низкая задержка записи.
Высокая пропускная способность (throughput) за счет батчинга.
Снижение нагрузки на БД.
Минусы:
Риск потери данных: Если кеш падает до синхронизации с БД, последние изменения теряются.
Сложность: Нужны механизмы отслеживания изменений, повтора при ошибках, "прогрева" кеша после перезапуска.
Согласованность eventual: БД отстает от кеша.
Где использовать: Для write-heavy нагрузок, где скорость записи и масштабируемость важнее 100% надежности. Пример: лайки, просмотры, метрики, аналитические события.
Заключение
Выбор паттерна — это компромисс между консисте��тностью, доступностью и производительностью.
Начинайте с Cache-Aside — он прост и предсказуем.
Для специализированных read-heavy сервисов присмотритесь к Read-Through.
Используйте Write-Through только для критически важных данных.
Внедряйте Write-Behind осторожно, осознавая риски потери данных, но для правильных задач он даст максимальный выигрыш в масштабируемости.
Часто в одной системе комбинируют несколько паттернов для разных типов данных.
