Карта / Кэширование / Двухуровневый кэш

Двухуровневый кэш

Двухуровневый кэш комбинирует быстрый локальный кэш (L1, в памяти приложения) с медленнее, но общим распределённым кэшем (L2, Redis). Идея — взять лучшее от обоих уровней.

Запрос → L1 (in-memory, наносекунды) → если нет → L2 (Redis, миллисекунды) → если нет → база данных
@Cacheable(value = "users", cacheManager = "twoLevelCacheManager")
User getUser(Long id) { ... }
Копнуть глубже

Зачем два уровня, если можно просто Redis. L1 (in-memory) — самый быстрый, потому что данные прямо в памяти текущего приложения, без сетевого похода. Но он не общий — если приложение работает в нескольких инстансах (несколько серверов за балансировщиком), у каждого свой отдельный L1, и они не синхронизированы между собой. L2 (Redis) — общий для всех инстансов, но требует сетевого запроса, медленнее.

Связка даёт: горячие, часто запрашиваемые данные — почти всегда находятся уже в L1 (максимальная скорость), а L2 служит подстраховкой и общим источником для синхронизации между инстансами.

Главная сложность — согласованность L1 между разными инстансами. Если данные изменились, нужно инвалидировать не только L2, но и L1 на всех инстансах приложения — это требует механизма уведомления (например, через Redis Pub/Sub: один инстанс публикует событие “user 5 изменился”, остальные слушают и сбрасывают свой L1 для этого ключа). Без этого механизма разные инстансы могут показывать разные (несогласованные) данные одному и тому же пользователю в зависимости от того, на какой сервер попал его запрос.

🎤 Закрыл тему, если можешь объяснить:
• зачем нужны два уровня кэша вместо одного Redis;
• в чём сложность согласованности L1 между несколькими инстансами приложения (если дошёл до 2-го слоя).