Caffeine
Introducción
Caffeine es una biblioteca de caché de alto rendimiento para Java.
Una diferencia fundamental entre una caché y un Map es que una caché expulsa elementos almacenados.
Una política de expulsión decide qué objetos deben eliminarse en un momento dado. Esta política afecta directamente a la tasa de aciertos de la caché, una característica crucial de las bibliotecas de caché.
Caffeine utiliza la política de expulsión Window TinyLfu, que proporciona una tasa de aciertos casi óptima.
Configuración de Caffeine
Primero, creemos un bean de Caffeine. Esta es la configuración principal que controlará el comportamiento de la caché, como la expiración, los límites de tamaño de la caché y más:
private CaffeineCache buildCaffeineCache(String name, CaffeineCacheSetting cacheSpec) {
log.info("Cache {} specified timeout of {} min, max of {}", name, cacheSpec.getTimeout(), cacheSpec.getMaxSize());
final Caffeine<Object, Object> caffeineBuilder =
Caffeine.newBuilder()
.expireAfterWrite(cacheSpec.getTimeout())
.maximumSize(cacheSpec.getMaxSize())
.recordStats();
return new CaffeineCache(name, caffeineBuilder.build());
}
A continuación, necesitamos otro bean usando la interfaz Spring CacheManager. Caffeine proporciona su implementación de esta interfaz, que requiere el objeto Caffeine que creamos arriba:
@Bean(name = "ipfCacheManager")
CacheManager ipfCaffeineCacheManager() {
SimpleCacheManager manager = new SimpleCacheManager();
if (Objects.nonNull(settings)) {
List<CaffeineCache> caches = settings.entrySet().stream()
.map(entry -> buildCaffeineCache(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
manager.setCaches(caches);
}
return manager;
}
Todos los beans mencionados anteriormente los obtenemos de forma gratuita al añadir la dependencia de maven mencionada antes.
Sin embargo, la caché de Caffeine requiere los siguientes valores de configuración para cada caché proporcionada:
ipf.caching.caffeine.settings."${cache_name}".timeout=[Duration]
ipf.caching.caffeine.settings."${cache_name}".max-size=[Long]
-
cache_name - nombre de la caché que se utiliza
-
timeout - duración durante la cual la caché permanecerá activa en memoria antes de ser expulsada.
-
max-size - tamaño máximo de la caché antes de que la caché expulse entradas que sea menos probable que se usen de nuevo ver Caffeine
Un ejemplo:
ipf.caching.caffeine.settings.cache1.timeout=10m
ipf.caching.caffeine.settings.cache1.max-size=10000
ipf.caching.caffeine.settings.cache2.timeout=20s
ipf.caching.caffeine.settings.cache2.max-size=100000
Implementación de Caffeine
La implementación es sencilla; como este módulo entiende spring boot, conectará todos los beans necesarios y los integrará en el Spring CacheManager proporcionando métricas.
Simplemente añade la dependencia de maven y luego recupera cualquier caché por nombre.
Obtenemos el bean CacheFactory de forma gratuita del módulo ipf-cache-caffeine y habilitando el caché de Caffeine.
@Bean(name = "caffeineCacheFactory")
CacheFactory<?, ?> cacheFactory(CacheManager cacheManager, CacheLogger<Object, Object> cacheLogger) {
return new CaffeineCacheFactory(cacheManager, cacheLogger);
}
Luego, solo necesitas usar la CacheFactory para crear un AsyncCacheAdapter:
@Bean
AsyncCacheAdapter<String, String> asyncCacheAdapter3(CacheFactory<String, String> cacheFactory) {
return cacheFactory.asyncCreateCacheAdapter(CACHE_3);
}
O un CacheAdapter:
@Bean
CacheAdapter<?, ?> cacheAdapter1(CacheFactory<?, ?> cacheFactory) {
return cacheFactory.createCacheAdapter(CACHE_1);
}
Dependencias
La dependencia en el módulo ipf-cache-api requiere algunas dependencias suministradas para leer y escribir en el registro de mensajes.
Estas pueden añadirse a tu aplicación (si no están presentes) de la siguiente manera:
@Bean
ObjectMapper objectMapper() {
return new ObjectMapper();
}
@Bean
MessageLogger messageLogger() {
return messageLogEntry -> log.info("log entry: {}", messageLogEntry);
}