Ответ
Локальный (in-memory) кэш хранит данные в оперативной памяти экземпляра сервиса. Его основная цель — резкое снижение задержки (latency) и нагрузки на нижележащие источники данных (базы данных, другие сервисы) для часто запрашиваемой, относительно статичной информации.
Цели и преимущества:
- Минимальная задержка: Доступ к данным из памяти на порядки быстрее, чем сетевой вызов или запрос к БД.
- Снижение нагрузки: Уменьшает количество запросов к БД или внешним API, защищая их от перегрузки.
- Устойчивость к сбоям: При недоступности основного источника данных сервис может какое-то время работать с устаревшими (кэшированными) данными.
- Простота: Легко реализуется с помощью библиотек (Caffeine, Ehcache) или фреймворков (Spring Cache).
Пример с Spring Cache и Caffeine:
@Service
public class CatalogService {
@Cacheable(value = "products", key = "#id")
public Product getProduct(Long id) {
// Дорогой вызов к БД выполняется только при промахе кэша
return productRepository.findById(id).orElseThrow();
}
}
// Конфигурация Caffeine для TTL и размера
@Configuration
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager();
manager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(1000));
return manager;
}
}
Компромиссы и проблемы:
- Несогласованность данных (Consistency): Каждый экземпляр сервиса имеет свою копию кэша. Изменение данных в одном экземпляре не обновляет кэш в других. Это проблема для данных, требующих сильной согласованности.
- Использование памяти: Кэш потребляет RAM, что ограничивает его объем и требует стратегий вытеснения (LRU, LFU).
- Сложность инвалидации: Актуальность данных зависит от TTL (время жизни) или явной инвалидации при обновлении.
Когда использовать: Для данных, которые часто читаются, редко меняются и допускают eventual consistency (справочники, конфигурация, статичный контент). Для синхронизации между инстансами или часто изменяющихся данных часто используют распределенный кэш (Redis, Hazelcast) поверх или вместо локального.