Кэширование в Java: Redis, Memcached и встроенные решения для профи

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

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

Начать курс

Кэширование в Java: Redis, Memcached и встроенные решения: продвинутый уровень

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

1. Встроенные кэши: Caffeine и Guava

Встроенные кэши работают внутри JVM и не требуют внешних сервисов. Они идеальны для хранения временных данных, которые не нужно синхронизировать между узлами.

Caffeine — современный стандарт

Caffeine — это высокопроизводительная библиотека для кэширования в Java, которая пришла на смену Guava Cache. Она использует алгоритм Window TinyLFU для эффективного вытеснения записей.

// Зависимость Maven
// <dependency>
//     <groupId>com.github.ben-manes.caffeine</groupId>
//     <artifactId>caffeine</artifactId>
//     <version>3.1.8</version>
// </dependency>

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;

import java.util.concurrent.TimeUnit;

public class CaffeineExample {
    public static void main(String[] args) {
        Cache<String, User> userCache = Caffeine.newBuilder()
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .maximumSize(10_000)
                .recordStats()
                .build();

        // Запись
        userCache.put("user:123", new User("Alice", "alice@example.com"));

        // Чтение
        User user = userCache.getIfPresent("user:123");
        System.out.println("Cached user: " + user);

        // Атомарное чтение с загрузкой
        User result = userCache.get("user:456", key -> loadUserFromDB(key));
    }

    private static User loadUserFromDB(String key) {
        // Имитация загрузки из БД
        return new User("Bob", "bob@example.com");
    }

    static class User {
        private final String name;
        private final String email;

        User(String name, String email) {
            this.name = name;
            this.email = email;
        }

        @Override
        public String toString() {
            return "User{name='" + name + "', email='" + email + "'}";
        }
    }
}

Guava Cache — проверенное решение

Guava Cache от Google остаётся популярным выбором для проектов, которые уже используют библиотеку Guava. Он поддерживает различные стратегии вытеснения и прослушиватели.

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class GuavaCacheExample {
    public static void main(String[] args) throws ExecutionException {
        LoadingCache<String, String> cache = CacheBuilder.newBuilder()
                .expireAfterAccess(5, TimeUnit.MINUTES)
                .maximumSize(5000)
                .removalListener(notification -> 
                    System.out.println("Removed: " + notification.getKey()))
                .build(new CacheLoader<String, String>() {
                    @Override
                    public String load(String key) {
                        return "Computed: " + key.toUpperCase();
                    }
                });

        // Запись
        cache.put("key1", "value1");

        // Чтение с автоматической загрузкой
        String value = cache.get("key2");
        System.out.println(value); // "Computed: KEY2"
    }
}

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

Redis — это in-memory хранилище данных, которое часто используется как распределённый кэш. В Java для работы с Redis чаще всего применяется библиотека Lettuce (асинхронная) или Jedis (синхронная).

Пример с Jedis

import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Jedis;

public class RedisCacheExample {
    private static final JedisPool pool = new JedisPool(
            new JedisPoolConfig(), "localhost", 6379);

    public static void main(String[] args) {
        try (Jedis jedis = pool.getResource()) {
            // Установка с TTL (Time-To-Live)
            jedis.setex("session:user1", 3600, "token_abc123");

            // Получение
            String token = jedis.get("session:user1");
            System.out.println("Token: " + token);

            // Пакетная вставка
            jedis.mset("key1", "value1", "key2", "value2");

            // Инкремент
            jedis.incr("counter:page_views");
        }
    }
}

Продвинутые возможности Redis

  • Pub/Sub — для уведомлений об инвалидации кэша
  • Redis Cluster — шардирование данных по нескольким узлам
  • Lua-скрипты — атомарные операции
  • Структуры данных — Hash, List, Set, Sorted Set

3. Memcached — простота и скорость

Memcached — это распределённая система кэширования с минималистичным API. В Java для взаимодействия используется библиотека Spymemcached или Xmemcached.

Пример с Spymemcached

import net.spy.memcached.MemcachedClient;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.Future;

public class MemcachedExample {
    public static void main(String[] args) throws IOException {
        MemcachedClient client = new MemcachedClient(
                new InetSocketAddress("localhost", 11211));

        // Установка с TTL (в секундах)
        Future<Boolean> setFuture = client.set("user:123", 3600, "{\"name\":\"Alice\"}");
        System.out.println("Set result: " + setFuture.isDone());

        // Получение
        Object cached = client.get("user:123");
        System.out.println("Cached value: " + cached);

        // Удаление
        client.delete("user:123");

        client.shutdown();
    }
}

Сравнение Redis vs Memcached

Характеристика Redis Memcached
Типы данных Строки, списки, х

Блоги

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