Кеш — это не просто «быстрая память». То, как ваше приложение взаимодействует с кешем, определяет согласованность данных, сложность кода и отказоустойчивость. Выбор паттерна зависит от сценариев нагрузки.

1. Cache-Aside (Lazy Loading) — Самый популярный паттерн

Принцип: Приложение управляет кешем напрямую. Кеш не обращается к источнику данных сам.

Алгоритм для чтения (Read):

  1. Приложение получает запрос на данные по ключу.

  2. Проверяет кеш. Если данные есть (Cache Hit) — возвращает их.

  3. Если данных нет (Cache Miss) — обращается к основной БД.

  4. Получает данные из БД, записывает их в кеш и возвращает клиенту.

Алгоритм для записи (Write):

  1. Приложение обновляет данные в основной БД.

  2. Инвалидирует (удаляет) соответствующий ключ в кеше.

Плюсы:

  • Простота: Легко понять и реализовать.

  • Отказоустойчивость: Если кеш упал, приложение продолжает работать напрямую с БД (правда, с повышенной нагрузкой).

  • Кеш содержит только реально запрашиваемые данные. Нет мусора.

Минусы:

  • Cache Miss Penalty: При промахе клиент ждет трех операций: проверка кеша, чтение из БД, запись в кеш.

  • Проблема согласованности (Coherency): Между обновлением БД и инвалидацией кеша возможна небольшая временная окно, когда кеш вернет устаревшие данные (stale data). Это eventual consistency.

  • «Грязное чтение»: Если два параллельных потока обработают промах на одни данные, оба прочитают из БД и попытаются записать в кеш (решается блокировками или условной записью).

Где использовать: Универсально для большинства сервисов, особенно с непредсказуемым или разнообразным доступом к данным. Классика для кеширования объектов пользователя, каталогов товаров.

2. Read-Through — Более «умный» кеш

Принцип: Приложение считает кеш основным источником данных. Кеш знает, как загружать данные из БД при промахе.

Алгоритм для чтения:

  1. Приложение всегда запрашивает данные только из кеша.

  2. Если данные есть — кеш возвращает их.

  3. Если данных нет — кеш сам загружает их из БД, сохраняет у себя и возвращает приложению.

Алгоритм для записи: Аналогичен Cache-Aside: приложение пишет в БД и инвалидирует кеш.

Плюсы:

  • Чище архитектура: Приложение не знает о БД, только о кеше.

  • Упрощение кода: Вся логика загрузки при промахе централизована в кеше (или его библиотеке).

  • Эффективнее при «прогретом» кеше: Уменьшает задержку для частых запросов.

Минусы:

  • Требует более сложной настройки кеша (или использования готовых решений, таких как распределенные кеши с этой функциональностью).

  • Первая загрузка (cold start) может быть болезненной: все запросы идут в БД, пока кеш не заполнится.

Где использовать: Идеально для read-heavy нагрузок с предсказуемыми ключами. Часто используется в комбинации с Write-Through/Write-Behind.

3. Write-Through — Кеш как «привратник» для записи

Принцип: Любая запись проходит сначала в кеш, а затем синхронно в БД. Кеш всегда актуален.

Алгоритм для записи:

  1. Приложение записывает данные в кеш.

  2. Кеш немедленно и синхронно записывает те же данные в БД.

  3. Операция считается успешной, только когда завершились оба действия.

Алгоритм для чтения: Используется Read-Through (запрос только к кешу).

Плюсы:

  • Полная согласованность данных (Strong Consistency): Гарантия, что данные в кеше и БД идентичны.

  • Надежность: Данные не потеряются при сбое, так как сразу сохранены в постоянное хранилище.

Минусы:

  • Высокая задержка записи (Write Latency): Клиент ждет завершения записи в (относительно медленную) БД.

  • Риск перегрузки БД: Каждая операция обновления кеша создает нагрузку на БД.

Где использовать: Для данных, где консистентность критически важнее производительности записи. Пример: финансовые транзакции, системные конфигурации.

4. Write-Behind (Write-Back) — Максимум производительности записи

Принцип: Приложение пишет только в кеш. Кеш подтверждает операцию немедленно, а затем асинхронно, пачками (batch) обновляет БД.

Алгоритм для записи:

  1. Приложение записывает данные в кеш.

  2. Кеш немедленно подтверждает успех клиенту.

  3. Через некоторое время (секунды, минуты) кеш пачкой скидывает накопленные изменения в БД.

Плюсы:

  • Очень низкая задержка записи.

  • Высокая пропускная способность (throughput) за счет батчинга.

  • Снижение нагрузки на БД.

Минусы:

  • Риск потери данных: Если кеш падает до синхронизации с БД, последние изменения теряются.

  • Сложность: Нужны механизмы отслеживания изменений, повтора при ошибках, "прогрева" кеша после перезапуска.

  • Согласованность eventual: БД отстает от кеша.

Где использовать: Для write-heavy нагрузок, где скорость записи и масштабируемость важнее 100% надежности. Пример: лайки, просмотры, метрики, аналитические события.

Заключение

Выбор паттерна — это компромисс между консисте��тностью, доступностью и производительностью.

  • Начинайте с Cache-Aside — он прост и предсказуем.

  • Для специализированных read-heavy сервисов присмотритесь к Read-Through.

  • Используйте Write-Through только для критически важных данных.

  • Внедряйте Write-Behind осторожно, осознавая риски потери данных, но для правильных задач он даст максимальный выигрыш в масштабируемости.

Часто в одной системе комбинируют несколько паттернов для разных типов данных.