Для кеширования результатов тяжёлых вычислений или редко меняющихся справочников Redis часто избыточен. Caffeine — высокопроизводительный in-process кеш с Window TinyLFU eviction policy.
🔹 Решение
▪️ Зависимость
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
▪️ Конфигурация через Spring Cache
spring:
cache:
type: caffeine
caffeine:
spec: maximumSize=1000,expireAfterWrite=10m
cache:
cache-names:
- currencies
- countryDictionary
- featureFlags
▪️ Программная конфигурация с разными политиками
@Configuration
@EnableCaching
public class CaffeineConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager();
manager.setCacheLoader(caffeineCacheLoader());
// разные настройки для разных кешей
manager.registerCustomCache("currencies",
buildCache(500, Duration.ofHours(1)));
manager.registerCustomCache("featureFlags",
buildCache(100, Duration.ofMinutes(5)));
// дефолт для остальных
manager.setCaffeine(Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.recordStats()); // метрики
return manager;
}
private Cache<Object, Object> buildCache(int size, Duration ttl) {
return Caffeine.newBuilder()
.maximumSize(size)
.expireAfterWrite(ttl)
.refreshAfterWrite(ttl.dividedBy(2)) // фоновое обновление
.recordStats()
.build();
}
}
▪️ Метрики через Micrometer
@Bean
public CacheMetricsRegistrar cacheMetricsRegistrar(MeterRegistry registry,
CacheManager cacheManager) {
return new CacheMetricsRegistrar(registry, List.of(cacheManager));
}
Даёт метрики: cache.gets, cache.puts, cache.evictions, cache.hits, hit rate.
refreshAfterWrite — ключевая настройка для production. В отличие от expireAfterWrite, он не удаляет запись по истечении TTL, а помечает её для фонового обновления. Следующий запрос получит устаревшее значение мгновенно, пока фоновый поток обновляет кеш. Латентность не растёт при рефреше.
⚠️ Caffeine — in-process кеш. При горизонтальном масштабировании каждый инстанс имеет свой кеш. Инвалидация при изменении данных требует либо короткого TTL, либо внешнего механизма (Redis pub/sub, Kafka event). Для справочников с редкими изменениями короткого TTL обычно достаточно.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise