Решение: какая стратегия кэширования?
Кэш хранит часто читаемые данные в быстром слое перед базой данных (например, Redis), снижая задержку и нагрузку на БД. Но не все данные подходят для кэширования, а неверная инвалидация создаёт риск устаревших/неверных данных. Это дерево сначала проверяет, действительно ли нужен кэш, затем помогает выбрать между cache-aside, read-through, write-through и write-behind по паттерну чтения/записи и рассматривает предотвращение stampede.
Как выглядит ваша нагрузка: преобладает чтение или запись?
Кэш окупается больше всего, когда одни и те же данные читаются много раз (преобладание чтения) и меняются нечасто. Сначала определите общий паттерн: данные много читаются и редко меняются, постоянно обновляются, или вы не уверены, стоит ли добавлять кэш?
- Сильное преобладание чтения, данные меняются относительно редко
- Записи тоже много; записанные данные читаются сразу/часто
- Не уверен; действительно ли мне нужен кэш?
Кто должен отвечать за наполнение кэша?
В сценарии с преобладанием чтения ключевой выбор — кто наполняет кэш. Должно ли приложение явно управлять кэшем и само обращаться к БД (высокая гибкость), или уровень кэша должен при промахе получать данные из базовой БД и прозрачно их возвращать?
- Пусть приложение управляет явно; мне нужны гибкость и контроль
- Пусть уровень кэша получает данные из БД при промахе (прозрачно)
При записи приоритет — согласованность или скорость записи?
Если записи много, нужно решить, насколько согласованными будут записанные данные между кэшем и БД. Обновлять ли кэш и БД вместе при каждой записи для гарантии согласованности (запись несколько медленнее), или запись сначала идёт в кэш и асинхронно применяется к БД в фоне (очень быстрая запись, но риск потерь)?
- Согласованность важна; чтение всегда должно быть актуальным
- Скорость записи критична; немного отложенная согласованность и риск потерь допустимы
Рекомендация: пока не добавляйте кэш
Кэш не бесплатен: он вносит проблему согласованности (устаревшие данные), дополнительную инфраструктуру и сложность инвалидации. Если запрос и так быстрый или данные меняются при каждом запросе, кэш не даёт выгоды, а лишь добавляет поверхность отказов.
Рекомендация: cache-aside (ленивая загрузка)
При cache-aside приложение сначала проверяет кэш; если данных нет (промах), оно читает их из БД, записывает в кэш и возвращает. Это самый распространённый и гибкий паттерн; кэш наполняется только реально запрашиваемыми данными.
Рекомендация: кэш read-through
При read-through приложение взаимодействует только с кэшем; при промахе уровень кэша сам получает данные из БД и наполняет кэш (через provider/loader). Код приложения упрощается, а логика наполнения находится в одном месте.
Рекомендация: кэш write-through
При write-through каждая запись идёт и в кэш, и в БД (синхронно); оба обновляются вместе. Поэтому кэш никогда не отстаёт от БД, а чтение всегда видит актуальные данные.
Рекомендация: кэш write-behind (write-back)
При write-behind запись сначала идёт в кэш и сразу возвращается пользователю; запись в БД выполняется в фоне асинхронно (пакетами/с задержкой). Скорость записи максимальна, но есть риски для надёжности и согласованности.