Caché en Kotlin: Redis, Caffeine y alternativas
El caché es una de las herramientas clave para mejorar el rendimiento de las aplicaciones. En Kotlin, gracias a la compatibilidad con Java y al rico ecosistema JVM, hay disponibles múltiples soluciones: desde un caché ligero en memoria hasta sistemas distribuidos basados en Redis. En este artículo analizaremos las bibliotecas populares, su configuración y ejemplos de uso.
¿Por qué es necesario el caché?
Los principales objetivos del caché son:
- Reducir el tiempo de respuesta (latencia) almacenando datos solicitados con frecuencia en memoria rápida.
- Disminuir la carga en bases de datos y APIs externas.
- Ahorrar recursos computacionales en solicitudes repetitivas.
Kotlin permite usar tanto bibliotecas nativas de Java como envoltorios especializados de Kotlin.
1. Redis a través de Lettuce o Redisson
Redis es el almacén de datos en memoria más popular para el caché distribuido. En Kotlin se conecta mediante los clientes Lettuce (reactivo) o Redisson (síncrono/asíncrono).
Ejemplo: caché con Lettuce
// build.gradle.ktsimplementation("io.lettuce:lettuce-core:6.3.1.RELEASE")
// CacheService.ktimport io.lettuce.core.RedisClientimport io.lettuce.core.api.sync.RedisCommands
class RedisCache(private val host: String = "localhost", private val port: Int = 6379) { private val client: RedisClient = RedisClient.create("redis://$host:$port") private val connection = client.connect() private val sync: RedisCommands<String, String> = connection.sync()
fun get(key: String): String? = sync.get(key) fun set(key: String, value: String, ttlSeconds: Long = 60) { sync.setex(key, ttlSeconds, value) } fun delete(key: String) = sync.del(key) fun close() { connection.close() client.shutdown() }}
// Usofun main() { val cache = RedisCache() cache.set("user:123", """{"name":"Alice","role":"admin"}""", 120) val data = cache.get("user:123") println(data) // {"name":"Alice","role":"admin"} cache.close()}Redisson — API de más alto nivel
implementation("org.redisson:redisson:3.27.2")
val config = Config().apply { useSingleServer().setAddress("redis://127.0.0.1:6379")}val redisson = Redisson.create(config)val map = redisson.getMap<String, String>("userCache")map["user:456"] = """{"name":"Bob"}"""val bob = map["user:456"]redisson.shutdown()2. Caffeine — caché rápido en memoria
Caffeine es el reemplazo moderno de Guava Cache. Está optimizado para altas cargas y admite la expulsión automática de entradas obsoletas.
implementation("com.github.ben-manes.caffeine:caffeine:3.1.8")
import com.github.benmanes.caffeine.cache.Cacheimport com.github.benmanes.caffeine.cache.Caffeineimport java.util.concurrent.TimeUnit
val cache: Cache<String, String> = Caffeine.newBuilder() .expireAfterWrite(10, TimeUnit.MINUTES) .maximumSize(10_000) .recordStats() .build()
// Escritura y lecturacache.put("key1", "value1")val value = cache.getIfPresent("key1")println(value) // value1
// Estadísticasval stats = cache.stats()println("Hit rate: ${stats.hitRate()}")3. Hazelcast — caché distribuido con agrupamiento
Hazelcast es adecuado para arquitecturas de microservicios: el caché se sincroniza automáticamente entre los nodos.
implementation("com.hazelcast:hazelcast:5.3.6")
import com.hazelcast.core.Hazelcastimport com.hazelcast.map.IMap
val instance = Hazelcast.newHazelcastInstance()val map: IMap<String, String> = instance.getMap("session-cache")map.put("session:token123", "userId=42", 30, TimeUnit.MINUTES)val userId = map.get("session:token123")instance.shutdown()4. Spring C
También en la biblioteca
Trabajo con archivos ZIP en Rust: biblioteca zip y guía completa
Migraciones de bases de datos en Java: revisión de herramientas y bibliotecas
Actix-web para Rust: guía completa con ejemplos
Generación de informes PDF en Rust: bibliotecas y ejemplos prácticos