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

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

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

Начать курс

Введение: Зачем нужно кэширование в Java?

В современной высоконагруженной разработке скорость доступа к данным — критический фактор. Каждый запрос к базе данных или внешнему API увеличивает время отклика и нагрузку на инфраструктуру. Кэширование в Java позволяет хранить часто запрашиваемые данные в быстродействующей памяти (RAM), сокращая время ответа с десятков миллисекунд до микросекунд.

В этой статье мы разберём три основных подхода к кэшированию: встроенные решения (HashMap, Caffeine, Ehcache), Redis и Memcached. Вы узнаете, как выбрать подходящий инструмент, и увидите рабочие примеры кода.

1. Встроенные решения для кэширования в Java

Для небольших проектов или однопоточных приложений часто достаточно встроенных коллекций. Однако для продакшн-среды лучше использовать специализированные библиотеки.

1.1. Простой кэш на HashMap

Самый простой способ — использовать ConcurrentHashMap с ручным управлением временем жизни. Подходит для прототипов, но не имеет механизмов вытеснения (eviction).

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

public class SimpleCache {
    private final ConcurrentHashMap<String, CacheEntry> cache = new ConcurrentHashMap<>();

    public void put(String key, Object value, long ttlMs) {
        cache.put(key, new CacheEntry(value, System.currentTimeMillis() + ttlMs));
    }

    public Object get(String key) {
        CacheEntry entry = cache.get(key);
        if (entry == null || System.currentTimeMillis() > entry.expiry) {
            cache.remove(key);
            return null;
        }
        return entry.value;
    }

    private record CacheEntry(Object value, long expiry) {}
}

1.2. Caffeine — высокопроизводительный кэш для Java

Caffeine — современная библиотека, используемая в Spring Cache. Поддерживает автоматическое вытеснение по времени, размеру и частоте использования.

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, String> cache = Caffeine.newBuilder()
                .expireAfterWrite(10, TimeUnit.MINUTES)
                .maximumSize(1000)
                .build();

        cache.put("user_1", "Алексей");
        String user = cache.getIfPresent("user_1");
        System.out.println(user); // Алексей
    }
}

1.3. Ehcache — корпоративный стандарт

Ehcache — зрелое решение с поддержкой кластеризации и персистентности на диск. Часто используется в связке с Hibernate.

import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;

public class EhcacheExample {
    public static void main(String[] args) {
        CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
                .withCache("users",
                        CacheConfigurationBuilder.newCacheConfigurationBuilder(
                                String.class, String.class,
                                ResourcePoolsBuilder.heap(100))
                ).build();
        cacheManager.init();

        Cache<String, String> cache = cacheManager.getCache("users", String.class, String.class);
        cache.put("user_2", "Мария");
        System.out.println(cache.get("user_2")); // Мария

        cacheManager.close();
    }
}

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

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

2.1. Подключение и базовые операции с Jedis

import redis.clients.jedis.Jedis;

public class RedisExample {
    public static void main(String[] args) {
        // Подключение к локальному Redis
        try (Jedis jedis = new Jedis("localhost", 6379)) {
            jedis.set("session:123", "user_token_abc");
            // Устанавливаем TTL 1 час
            jedis.expire("session:123", 3600);

            String value = jedis.get("session:123");
            System.out.println("Получено: " + value); // user_token_abc
        }
    }
}

2.2. Кэширование объектов с сериализацией

Для кэширования сложных объектов используйте сериализацию (например, JSON или Java Serialization).

import com.fasterxml.jackson.databind.ObjectMapper;
import redis.clients.jedis.Jedis;

public class RedisObjectCache {
    private static final ObjectMapper mapper = new ObjectMapper();

    public static void main(String[] args) throws Exception {
        User user = new User("ivan", "ivan@example.com");
        try (Jedis jedis = new Jedis()) {
            String json = mapper.writeValueAsString(user);
            jedis.setex("user:ivan", 600, json); // TTL 10 минут

            String cached = jedis.get("user:ivan");
            User cachedUser = mapper.readValue(cached, User.class);
            System.out.println(cachedUser.email()); // ivan@example.com
        }
    }

    record User(String name, String email) {}
}

3. Memcached — простое и быстрое кэширование

Memcached — распределённая система кэширования, ориентированная на простоту. В отличие от Redis, не поддерживает персистентность и сложные структуры, но работает быстрее на базовых операциях get/set. Для Java используется библиотека Spymemcached.

3.1. Пример работы с Spymemcached

import net.spy.memcached.MemcachedClient;
import java.net.InetSocketAddress;

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

            // Сохраняем значение на 1 час (3600 секунд)
            client.set("page:home", 3600, "<html>...</html>");

            Object cached = client.get("page:home");
            System.out.println("Кэш: " + cached);
        }
    }
}

Сравнение: когда что выбрать?

КритерийВстроенные решенияRedisMemcached
СкоростьВысокая (in-process)Высокая (сеть)Очень высокая
Перси

Блоги

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