Кэширование в Kotlin: Redis, Memcached и встроенные решения от А до Я

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Кэширование в Kotlin: Redis, Memcached и встроенные решения — от А до Я

Кэширование — один из ключевых инструментов для повышения производительности приложений. В экосистеме Kotlin, который работает поверх JVM и Android, разработчику доступно множество решений: от распределённых систем (Redis, Memcached) до встроенных локальных кэшей (Caffeine, Guava Cache, Ehcache). В этой статье мы разберём, как интегрировать каждый из них в Kotlin-проект, приведём примеры кода и дадим рекомендации по выбору.

1. Встроенное кэширование на JVM: Caffeine и Guava Cache

Для локального кэширования в Kotlin лучше всего подходит Caffeine — высокопроизводительная библиотека, написанная на Java и полностью совместимая с Kotlin. Она поддерживает автоматическую выгрузку по времени, по размеру и на основе весов. Альтернатива — Guava Cache от Google, но Caffeine быстрее (часто в 2-3 раза).

Пример: Caffeine + Kotlin

Добавьте зависимость в build.gradle.kts:

implementation("com.github.ben-manes.caffeine:caffeine:3.1.8")

Создаём кэш на 1000 элементов с TTL 10 минут:

import com.github.benmanes.caffeine.cache.Caffeine
import java.util.concurrent.TimeUnit

val cache = Caffeine.newBuilder()
    .maximumSize(1000)
    .expireAfterWrite(10, TimeUnit.MINUTES)
    .build<String, String>()

// Использование
cache.put("user:42", "{\"name\":\"Alice\"}")
val user = cache.getIfPresent("user:42")
println(user) // {"name":"Alice"}

Пример: Guava Cache + Kotlin

implementation("com.google.guava:guava:33.0.0-jre")
import com.google.common.cache.CacheBuilder
import java.util.concurrent.TimeUnit

val guavaCache = CacheBuilder.newBuilder()
    .maximumSize(500)
    .expireAfterWrite(5, TimeUnit.MINUTES)
    .build<String, String>()

guavaCache.put("session:abc", "active")
println(guavaCache.getIfPresent("session:abc")) // active

Когда использовать: для хранения временных данных одного экземпляра приложения (например, результатов сложных вычислений, токенов, конфигураций). Не подходит для микросервисов с несколькими инстансами — данные не синхронизируются.

2. Redis — распределённое кэширование для микросервисов

Redis — это in-memory хранилище типа «ключ-значение», которое используется как распределённый кэш, брокер сообщений и база данных. Для Kotlin лучший клиент — Lettuce (асинхронный, реактивный, thread-safe).

Установка и подключение

implementation("io.lettuce:lettuce-core:6.3.2.RELEASE")

Пример: подключение и базовые операции

import io.lettuce.core.RedisClient
import io.lettuce.core.api.sync.RedisCommands

val client = RedisClient.create("redis://localhost:6379")
val connection = client.connect()
val commands: RedisCommands<String, String> = connection.sync()

// Устанавливаем ключ с TTL 60 секунд
commands.setex("user:123", 60, "{\"name\":\"Bob\"}")

// Читаем
val data = commands.get("user:123")
println(data) // {"name":"Bob"}

connection.close()
client.shutdown()

Пример: реактивный клиент (Kotlin Coroutines)

import io.lettuce.core.RedisClient
import io.lettuce.core.api.reactive.RedisReactiveCommands
import kotlinx.coroutines.reactive.awaitFirstOrNull

suspend fun getFromRedis(key: String): String? {
    val client = RedisClient.create("redis://localhost:6379")
    val connection = client.connect()
    val reactive: RedisReactiveCommands<String, String> = connection.reactive()

    val result = reactive.get(key).awaitFirstOrNull()
    connection.close()
    client.shutdown()
    return result
}

Когда использовать: распределённые системы, микросервисы, общие сессии, rate limiting, pub/sub. Redis — стандарт де-факто для кэширования в продакшене.

3. Memcached — лёгкий и быстрый распределённый кэш

Memcached — ещё один in-memory кэш, но с более простой моделью (только ключ-значение, без persistence, без сложных структур данных). Для Kotlin используем клиент Xmemcached.

Подключение

implementation("com.googlecode.xmemcached:xmemcached:2.4.8")

Пример: работа с Memcached

import net.rubyeye.xmemcached.MemcachedClientBuilder
import net.rubyeye.xmemcached.XMemcachedClient

val client = XMemcachedClient("localhost", 11211)

// Сохраняем на 30 секунд
client.set("page:home", 30, "<html>cached content</html>")

// Читаем
val cachedPage = client.get<String>("page:home")
println(cachedPage) // cached content

client.shutdown()

Когда использовать: когда требуется максимальная простота и скорость, не нужна персистентность, и данные «живут» недолго (например, кэш HTML-фрагментов, результаты быстрых запросов). Memcached быстрее Redis на простых операциях get/set, но уступает в функциональности.

4. Сравнение и выбор решения

Ниже — сводная таблица для быстрого выбора:

  • Caffeine / Guava Cache — локальный кэш одного процесса. Скорость: максимальная (наносекунды). Не требует сети. Подходит для Android и монолитов.
  • Redis — распределённый, с поддержкой структур (списки, хэши, сеты), pub/sub, Lua-скриптов. Скорость: микросекунды по сети. Требует отдельного сервера.
  • Memcached — распределённый, простой, быстрый. Скорость: микросекунды. Не поддерживает persistence. Хорош для кэша сессий и простых данных.

Для Android-приложений оптимальный выбор — Caffeine (или даже LruCache из Android SDK). Для серверных проектов на Kotlin часто используют комбинацию: Caffeine для локального кэша (L1) + Redis для распределённого (L2).

Блоги

Рекомендаций по книгам