Какие стратегии инвалидации кэша существуют?
Инвалидация кэша — это процесс удаления или обновления устаревших данных в кэше, являющийся самой сложной частью кэширования.
Аналогия из жизни: инвалидация кэша — как обновление расписания на информационном стенде. Если расписание изменилось, но стенд не обновили, люди будут приходить в неправильное время. Вопрос в том, как и когда обновлять стенд.
1. TTL (Time-To-Live)
Самая простая стратегия — данные автоматически удаляются через заданное время.
Пример
@Cacheable(value = "users", key = "#id") // TTL задаётся в конфигурации CacheManager
public User findById(Long id) { ... }
Пример
SET user:1 '{"name":"John"}' EX 600 # удалится через 10 минут
Плюсы: простота; гарантия, что данные не старше TTL. Минусы: в пределах TTL данные могут быть устаревшими; после TTL — cache miss.
2. Явная инвалидация (Event-Driven)
При обновлении данных явно удаляем/обновляем кэш.
Пример
@CacheEvict(value = "users", key = "#id")
public void updateUser(Long id, UpdateRequest request) {
userRepository.save(toEntity(id, request));
}
// Или через события (в микросервисах)
@TransactionalEventListener
public void onUserUpdated(UserUpdatedEvent event) {
cacheManager.getCache("users").evict(event.getUserId());
}
В микросервисах сервис публикует событие в Kafka, потребители инвалидируют свои кэши:
Пример кода
// Сервис A: обновил пользователя → опубликовал событие
@Transactional
public void updateUser(Long id, UpdateRequest request) {
userRepository.save(toEntity(id, request));
kafkaTemplate.send("user-events", new UserUpdatedEvent(id));
}
// Сервис B: получил событие → инвалидировал свой кэш
@KafkaListener(topics = "user-events")
public void onUserEvent(UserUpdatedEvent event) {
cacheManager.getCache("users").evict(event.getUserId());
}
3. Write-Through / Write-Behind
Кэш обновляется одновременно с БД (Write-Through) или асинхронно (Write-Behind). Подробнее см. раздел “Паттерны кэширования”.
4. Version-based (ETag)
Каждая запись имеет версию. При чтении из кэша проверяется, не изменилась ли версия в БД.
Пример
// Быстрая проверка версии (один лёгкий запрос к БД)
Long cachedVersion = cache.get("user:" + id + ":version");
Long currentVersion = userRepository.getVersion(id);
if (!currentVersion.equals(cachedVersion)) {
// Версия изменилась — обновить кэш
cache.put("user:" + id, userRepository.findById(id));
cache.put("user:" + id + ":version", currentVersion);
}
5. Pub/Sub-инвалидация (для распределённых кэшей)
Redis Pub/Sub для уведомления всех экземпляров приложения:
Пример
// При обновлении — публикуем в канал
redisTemplate.convertAndSend("cache-invalidation", "users:" + id);
// Все экземпляры слушают канал
@Component
public class CacheInvalidationListener implements MessageListener {
@Override
public void onMessage(Message message, byte[] pattern) {
String key = new String(message.getBody());
caffeineCache.invalidate(key); // инвалидируем L1 (in-memory)
}
}
Сравнение стратегий
| Стратегия | Согласованность | Сложность | Применение |
|---|---|---|---|
| TTL | Eventual (в пределах TTL) | Низкая | Справочники, каталоги |
| Явная инвалидация | Высокая | Средняя | CRUD-операции |
| Event-driven (Kafka) | Eventual | Высокая | Микросервисы |
| Write-Through | Strong | Средняя | Критичные данные |
| Version-based | Strong | Средняя | Когда TTL неприемлем |
Выводы
- TTL + явная инвалидация — наиболее распространённая комбинация: TTL как страховка,
@CacheEvictпри обновлении - В микросервисах: событийная инвалидация через Kafka/Redis Pub/Sub
- Стратегия “cache aside + TTL + evict on update” покрывает 90% сценариев
Частые ошибки
- Обновить БД, забыть инвалидировать кэш — пользователи видят старые данные
- Инвалидировать кэш ДО записи в БД — при ошибке записи кэш пуст, следующий запрос загрузит старые данные из БД
- Правильный порядок: сначала запись в БД, потом инвалидация кэша
- TTL слишком большой — 24 часа для профиля пользователя = показывать вчерашнее имя
- TTL слишком маленький — 1 секунда для справочника = нет смысла кэшировать
Как используется в 2026
- TTL +
@CacheEvict— стандарт в Spring-приложениях - Kafka-based инвалидация — стандарт в микросервисах
- Redis keyspace notifications — автоматическое уведомление об истечении TTL
На собеседовании: интервьюер хочет услышать про комбинацию TTL + явная инвалидация и правильный порядок операций (сначала БД, потом кэш). Частая ошибка — не знать про event-driven инвалидацию в микросервисах.