Что делать когда достигается предельный размер Cache
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Обработка переполнения Cache
Когда cache достигает своего предельного размера (capacity), необходимо применить стратегию вытеснения (eviction policy) для удаления старых или менее используемых записей. Выбор правильной стратегии критичен для производительности приложения.
Основные стратегии вытеснения
LRU (Least Recently Used) — удаляются данные, которые дольше всего не использовались. Это одна из самых популярных и эффективных стратегий для большинства приложений.
LFU (Least Frequently Used) — удаляются элементы с наименьшим количеством обращений. Полезна, когда частота использования важнее времени последнего доступа.
FIFO (First In First Out) — удаляются элементы в порядке их добавления в кэш. Простая, но часто неэффективная стратегия.
TTL (Time To Live) — элементы удаляются по истечении установленного времени жизни, независимо от использования.
Реализация LRU Cache в Java
import java.util.LinkedHashMap;
import java.util.Map;
public class LRUCache<K, V> {
private final int capacity;
private final LinkedHashMap<K, V> cache;
public LRUCache(int capacity) {
this.capacity = capacity;
// LinkedHashMap с accessOrder=true отслеживает порядок доступа
this.cache = new LinkedHashMap<K, V>(capacity, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > capacity;
}
};
}
public synchronized V get(K key) {
return cache.get(key); // обновляет порядок доступа
}
public synchronized void put(K key, V value) {
cache.put(key, value);
// Если размер превышен, LinkedHashMap автоматически
// удалит least recently used элемент
}
public synchronized int size() {
return cache.size();
}
}
// Использование
LRUCache<String, String> cache = new LRUCache<>(100);
cache.put("user:1", "John Doe");
String value = cache.get("user:1");
Использование Guava Cache с вытеснением
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.util.concurrent.TimeUnit;
public class UserCache {
private final Cache<String, User> cache;
public UserCache() {
cache = CacheBuilder.newBuilder()
.maximumSize(10000) // максимум 10000 элементов
.expireAfterWrite(10, TimeUnit.MINUTES) // TTL 10 минут
.recordStats() // собирать статистику
.build();
}
public User getUser(String userId) {
return cache.getIfPresent(userId);
}
public void putUser(String userId, User user) {
cache.put(userId, user);
}
public void printStats() {
System.out.println(cache.stats());
}
}
Использование Spring Cache с вытеснением
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import java.util.concurrent.TimeUnit;
@Configuration
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("users", "products");
cacheManager.setCaffeine(Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(15, TimeUnit.MINUTES)
.recordStats());
return cacheManager;
}
}
@Service
public class UserService {
@Cacheable("users")
public User findById(String id) {
// если cache переполнен, Caffeine автоматически удалит
// LRU элемент
return userRepository.findById(id);
}
@CacheEvict("users", key = "#id")
public void updateUser(String id, User user) {
userRepository.save(user);
}
}
Мониторинг и управление Cache
public class CacheMonitor {
private final Cache<String, User> cache;
public void monitorCache() {
// Проверка размера
if (cache.size() > capacity * 0.8) {
logger.warn("Cache usage is at 80% capacity");
}
// Ручная очистка при необходимости
cache.invalidateAll(); // очистить всё
cache.invalidate(key); // удалить конкретный ключ
}
}
Выбор стратегии в зависимости от сценария
| Стратегия | Когда использовать | Пример |
|---|---|---|
| LRU | Общий случай, веб-приложения | Кэш пользовательских данных |
| LFU | Неравномерное распределение обращений | Кэш популярных товаров |
| TTL | Данные с истечением актуальности | Сессии, токены доступа |
| FIFO | Когда порядок важен | Очереди сообщений |
Лучшие практики
- Выбирайте правильный размер cache в зависимости от доступной памяти
- Используйте готовые библиотеки (Guava, Caffeine) вместо самодельных реализаций
- Мониторьте hit rate и miss rate cache для анализа эффективности
- Применяйте TTL для данных, которые могут устаревать
- Используйте асинхронную загрузку данных, чтобы избежать блокировок
Правильное управление переполнением cache — это ключ к сбалансированной производительности приложения.