Caffeine Cache, некоронованный король локального кэша
Caffeine Cache, некоронованный король локального кэша

Количество слов в статье: 6867 слов. Чтение занимает около 8 минут.

В обычном процессе разработки программного обеспечения важность кэширования становится все более заметной. Это не только сокращает время обратной связи с пользователями, но и в большинстве случаев эффективно снижает нагрузку на систему.

В этой статье будет подробно рассказано о местномкэшрамка:「Caffeine Cache」。

Caffeine Cacheс его высокой производительностьюи Масштабируемость побеждает「Король локального кэширования」заголовок,Это кэш-библиотека Java. Целью его разработки является оптимизация скорости вычислений, эффективности памяти и практичности.,для удовлетворения потребностей современных разработчиков программного обеспечения.

Локальным кешем по умолчанию в версии Spring Boot 1.x является Guava Cache. После Spring 5 (SpringBoot 2.x) Spring официально отказался от Guava Cache в качестве механизма кэширования и вместо этого использовал Caffeine, который имеет более высокую производительность, в качестве компонента кэширования по умолчанию. Это большое подтверждение для Caffeine.

Далее мы подробно представим функции и приложения Caffeine Cache и органично интегрируем этот эффективный инструмент кэширования в ваш проект.

алгоритм исключения

Разбор кофеина Прежде чем использовать Cache, мы должны сначала понять кэшалгоритм. исключение. Отличный алгоритм Исключение может значительно повысить эффективность, поскольку процесс кэширования всегда сопровождается уничтожением данных.

  • ФИФО (первым пришел — первым обслужен):

В зависимости от времени данные, которые первыми попадают в кэш, будут удалены первыми. Когда кэш заполнен, самые ранние данные, помещенные в кэш, удаляются.

Преимущества: Простота реализации, лучше подходит для некоторых приложений с нечасто повторяющимися запросами.

Недостатки: Частота доступа и время доступа к элементам данных не учитываются, а самые последние и часто используемые данные могут быть удалены.

  • LRU (наименее недавно использованный) не использовался в течение длительного времени:

Этот алгоритм принимает решения на основе исторических записей доступа к данным, и данные, к которым не было доступа в течение длительного времени, будут удалены. LRU поддерживает связанный список всех элементов кэша. Новые данные вставляются в заголовок связанного списка. Если кэш заполнен, данные будут удалены из конца связанного списка.

Преимущества: LRU учитывает последние шаблоны доступа к данным, имеет отличную производительность по принципу локальности, прост и практичен.

Недостатки: он не может отражать частоту доступа к данным. Если к данным обращались недавно, они не будут удалены, даже если частота доступа низкая. Например, если к фрагменту данных часто обращаются в первые 59 секунд минуты и нет доступа в последнюю секунду, но пакет непопулярных данных попадает в кэш в последнюю секунду, то «горячие» данные могут быть удалены.

  • LFU (наименее часто используемый) В последнее время наименее часто используемый:

Основной принцип заключается в подсчете каждого объекта в кэше и записи количества обращений к нему. Когда кэш заполнен и некоторые объекты необходимо удалить, алгоритм LFU отдает приоритет объектам, к которым обращались реже всего.

Преимущества: LFU может лучше справляться с ситуациями, когда долгосрочный доступ является стабильным и частым, поскольку это гарантирует, что часто используемые объекты не будут легко удалены.

Недостатки: LFU не может эффективно обрабатывать некоторые объекты, к которым часто временно обращаются, но которые впоследствии больше не используются. Поскольку время доступа к этим объектам уже очень велико, даже если в дальнейшем к ним больше не будет доступа, их будет нелегко устранить, что может привести к пустой трате места в кэше. А LFU необходимо поддерживать счетчики доступа ко всем объектам, которые могут занимать много места для хранения и вычислительных ресурсов.

  • W-TinyLFU( Window Tiny Least Frequently Used):

Caffeine использует стратегию устранения Window TinyLfu, которая обеспечивает почти оптимальную результативность.

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

Как это работает:

  1. Частотная фильтрация: W-TinyLFU Используйте небольшое скользящее окно недавно посещенного объекта, чтобы отследить частоту использования объекта. данные в этом окне вставляются в LFU Счетчик, который очищает наименее используемые значения в зависимости от частоты.
  2. Внезапная адаптация: W-TinyLFU Также содержит Admission Window,Используется для отслеживания вновь добавленных предметов в кэш.,Для того, чтобы иметь возможность обрабатывать новые горячие точки, которые внезапно появляются в данных.
  3. Стратегия замены: когда кэш заполнен,И когда есть новые элементы, которые необходимо добавить,W-TinyLFU Используйте информацию о частоте, чтобы выбрать наименее используемые записи для замены. Если новый элемент используется чаще, он заменит старый элемент, который используется реже; если новый элемент используется реже, он может быть отклонен.

По сравнению с традиционными стратегиями LRU и LFU, W-TinyLFU имеет следующие преимущества:

  1. Сбалансированная давность и частота: с LRU По сравнению с W-TinyLFU Учитывается не только недавнее использование, но и рассчитывается популярность кэша. и LFU Для сравнения, он не занимает много места с данными, которые были очень популярны когда-то, но сейчас используются редко.
  2. Ограничения счетчика: TinyLFU использует счетный фильтр фиксированного размера для отслеживания частоты доступа, что значительно снижает объем используемой памяти по сравнению с традиционными стратегиями LFU.
  3. Адаптируемость: W-TinyLFU может лучше адаптироваться к изменениям рабочей нагрузки, поскольку у него есть временное окно для подсчета частот. Это позволяет W-TinyLFU не придавать слишком большого значения более ранним шаблонам доступа и быстрее адаптироваться к более поздним шаблонам доступа.
  4. Избегайте загрязнения кэша: поскольку он сохраняет admission окно, которое позволяет избежать возможного загрязнения, вызванного одноразовыми и крупномасштабными запросами.

недостаток:

  1. Необходимо поддерживать дополнительную информацию о частоте, что добавляет некоторые накладные расходы.
  2. Его не так просто реализовать, как алгоритм LRU. Для различных сценариев использования необходимо настроить параметры для достижения наилучшей производительности.

В общем, W-TinyLFU — это очень сложный и гибкий алгоритм кэширования, который хорошо справляется с идентификацией и обработкой долговременных и пакетных «горячих» данных, но по сравнению с более простыми алгоритмами, такими как LRU, он требует больше ресурсов и точной настройки.

Тип кэша

Caffeine предоставляет в общей сложности четыре типа кэша, соответствующие четырем стратегиям загрузки.

Cache

Самый распространенный вид кэша,Нет необходимости указывать метод загрузки,Приходится вызывать вручнуюput()загрузить。Нужно обратить вниманиеда,Метод put() перезапишет существующий ключ.

При получении значения кэша,Если вы хотите использовать кэш, когда значение не существует,Атомарно записывает значение в кэш,тогда ты можешь позвонитьget(key, k -> value)метод,Этот метод позволит избежать конфликтов при записи.

Во многих случаях,при использованииget(key, k -> value)час,Если есть еще один вызов этого метода в то же время, чтобы конкурировать,Тогда последний будет заблокирован,до предыдущегонитьвозобновлятькэш Заканчивать;И если другойнитьвызовgetIfPresent()метод,немедленно вернет ноль,Не будет заблокирован.

Язык кода:javascript
копировать
Cache<String, String> cache = Caffeine.newBuilder().build();

cache.getIfPresent("1");    // null
cache.get("1", k -> 1);    // 1
cache.getIfPresent("1");   //1
cache.set("1", "2");
cache.getIfPresent("1");   //2

Loading Cache

LoadingCacheда Своеобразная автоматическая загрузка кэша. Отличие его от обычного кэша в том, что,Если кэш не существует или срок его действия истек, при вызове метода get() будет автоматически вызван метод CacheLoader.load() для загрузки последнего значения. Вызов метода getAll() будет проходить по всем ключам и вызывать get(. ), если не реализован метод CacheLoader().

При использовании LoadingCache вам необходимо указать CacheLoader и реализовать его метод load() для автоматической загрузки при отсутствии кеша.

Во многих случаях,когда дванить同часвызовget(),Тогда последний будет заблокирован,Пока не завершится предыдущее обновление кэша.

Язык кода:javascript
копировать
LoadingCache<String, Object> cache = Caffeine.newBuilder().build(new CacheLoader<String, Object>() {
            @Override
            public @Nullable Object load(@NonNull String s) {
                return «Читать из библиотеки данных»;
            }

            @Override
            public @NonNull Map<@NonNull String, @NonNull Object> loadAll(@NonNull Iterable<? extends @NonNull String> keys) {
                return null;
            }
        });

cache.getIfPresent("1"); // null
cache.get("1");          // Чтение из библиотеки данных
cache.getAll(keys);      // null

LoadingCache особенно практичен. Мы можем настроить логику в методе загрузки и загружать ее из базы данных, когда кэш не существует. Это может обеспечить многоуровневое кэширование.

Async Cache

Вариант AsyncCacheCache.,Все результаты ответовCompletableFuture

таким образом,AsyncCache адаптирует асинхронное программирование. По умолчанию,кэш Рассчитайте, используяForkJoinPool.commonPool()какнитьбассейн,Если вы хотите указать нить пула,то вы можете переопределить и реализоватьCaffeine.executor(Executor)метод。

В многопоточной ситуации, когда два потока вызывают get(key, k -> value),вернется「Тот же объект CompletableFuture」。Поскольку сам возвращаемый результат не блокирует,Вы можете выбрать ожидание блокировки или неблокировку в соответствии с дизайном вашего бизнеса.

Язык кода:javascript
копировать
import com.github.benmanes.caffeine.cache.AsyncCache;
import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class CaffeineExample {
    private final Executor executor = Executors.newSingleThreadExecutor();

    CacheLoader<String, String> loader = new CacheLoader<>() {
        @Override
        public String load(String key) throws Exception {
            // Имитировать процесс загрузки данных
            Thread.sleep(1000);
            return key.toUpperCase();
        }

        @Override
        public CompletableFuture<String> asyncLoad(String key, Executor executor) {
            return CompletableFuture.supplyAsync(() -> {
                try {
                    return load(key);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }, executor);
        }
    };

    AsyncCache<String, String> cache = Caffeine.newBuilder()
            .maximumSize(100)
            .executor(executor)
            .buildAsync(loader);

    public void test() throws Exception {
        // Асинхронный сбор
        CompletableFuture<String> future = cache.get("hello");
        System.out.println(future.get());  // выход HELLO
    }

    public static void main(String[] args) throws Exception {
        new CaffeineExample().test();
    }
}

Async Loading Cache

Вы можете сказать это по названию: очевидно, это Загрузка. Кэш и асинхронность Cacheкомбинация функций。Async Loading Cache поддерживает автоматическую загрузку кешей асинхронно.

Вот пример того, как создать кэш асинхронной загрузки:

Язык кода:javascript
копировать
import com.github.benmanes.caffeine.cache.AsyncLoadingCache;
import com.github.benmanes.caffeine.cache.Caffeine;

// создавать AsyncLoadingCache
AsyncLoadingCache<String, Data> cache = Caffeine.newBuilder()
    .maximumSize(10000)
    .expireAfterWrite(5, TimeUnit.MINUTES)
    .buildAsync(this::loadData);

// Определить метод загрузки
private CompletableFuture<Data> loadData(String key) {
    // Это всего лишь пример, вы можете выполнить операцию загрузки в соответствии с реальной ситуацией.
    return CompletableFuture.supplyAsync(() -> {
        // Загрузите данные из библиотеки данных или из другого места.
        Data data = ... ;
        return data;
    });
}

// Используйте кэш
public void useCache(String key) {
    cache.get(key).thenAccept(data -> {
        // Здесь данные да loadData метод возвращает объект
        // ХОРОШО data Процесс
       ...
    });
}

Кэш асинхронной загрузки также очень практичен. В некоторых бизнес-сценариях загрузка данных занимает много времени. В этом случае кэш асинхронной загрузки можно использовать, чтобы избежать блокировки загрузки данных.

стратегия выселения

Кофеин предлагает три стратегии переработки: переработка по размеру, переработка по времени и переработка по эталонам.

Срок действия в зависимости от размера

Существует два способа стратегии переработки на основе размера: один основан на размере кэша, а другой — на весе.

Язык кода:javascript
копировать
// Выселение на основании подсчёта кэша
LoadingCache<String, Object> cache = Caffeine.newBuilder()
    .maximumSize(10000)
    .build(new CacheLoader<String, Object>() {

            @Override
            public @Nullable Object load(@NonNull String s) {
                return «Читать из библиотеки данных»;
            }

            @Override
            public @NonNull Map<@NonNull String, @NonNull Object> loadAll(@NonNull Iterable<? extends @NonNull String> keys) {
                return null;
            }
        });


// Выселения производятся в зависимости от веса кэша. Те, у кого вес меньше, будут выселены в первую очередь.
LoadingCache<String, Object> cache1 = Caffeine.newBuilder()
    .maximumWeight(10000)
    .weigher(new Weigher<String, Object>() {
                    @Override
                    public @NonNegative int weigh(@NonNull String s, @NonNull Object o) {
                        return 0;
                    }
                })
    .build(new CacheLoader<String, Object>() {
            @Override
            public @Nullable Object load(@NonNull String s) {
                return «Читать из библиотеки данных»;
            }

            @Override
            public @NonNull Map<@NonNull String, @NonNull Object> loadAll(@NonNull Iterable<? extends @NonNull String> keys) {
                return null;
            }
        });

Уведомление:MaximumWeight и MaximumSize не могут использоваться одновременно.,Это потому, что оба механизма используются для ограничения размера кэша. Необходимо сделать выбор между этими двумя.

Срок действия по времени

Язык кода:javascript
копировать
// Выход на основе различных стратегий истечения срока действия
LoadingCache<String, Object> cache = Caffeine.newBuilder()
    .expireAfter(new Expiry<String, Object>() {
        @Override
        public long expireAfterCreate(String key, Object value, long currentTime) {
            return TimeUnit.SECONDS.toNanos(seconds);
        }

        @Override
        public long expireAfterUpdate(@Nonnull String s, @Nonnull Object o, long l, long l1) {
            return 0;
        }

        @Override
        public long expireAfterRead(@Nonnull String s, @Nonnull Object o, long l, long l1) {
            return 0;
        }
    }).build(key -> function(key));

Кофеин предлагает три типа стратегии выбора времени. выселения:

  • expireAfterAccess(long, TimeUnit):существовать最后一次访问或者写入后开始计час,Срок действия истекает по истечении указанного времени. Если всегда есть запросы на доступ к ключу,Тогда этот кэш никогда не истечет.
  • expireAfterWrite(long, TimeUnit):при последней записикэш后开始计час,Срок действия истекает по истечении указанного времени.
  • expireAfter(Expiry):Пользовательская стратегия,Срок действия рассчитывается независимо реализацией Expiry.

Срок действия на основе ссылки

Четыре ссылочных типа в Java

ссылочный тип

Время сбора мусора

использовать

время выживания

Сильная ссылка Сильная ссылка

никогда

общее состояние объекта

Завершить работу, когда JVM перестанет работать

Мягкая ссылка Мягкая ссылка

Когда недостаточно памяти

кэш объектов

Завершить из-за недостаточности памяти

Слабая ссылка

во время сбора мусора

кэш объектов

gc завершает работу после запуска

Фантомная ссылка Фантомная ссылка

никогда

Виртуальные ссылки можно использовать для отслеживания активности объектов, перерабатываемых сборщиком мусора. Когда объект, связанный с виртуальной ссылкой, перерабатывается сборщиком мусора, будет получено системное уведомление.

Завершить работу, когда JVM перестанет работать

Язык кода:javascript
копировать
// Вытеснить кэш, если не указан ни ключ, ни значение.
LoadingCache<String, Object> cache = Caffeine.newBuilder()
    .weakKeys()
    .weakValues()
    .build(key -> function(key));

// Вытеснение, когда сборщику мусора необходимо освободить память
LoadingCache<String, Object> cache1 = Caffeine.newBuilder()
    .softValues()
    .build(key -> function(key));

Уведомление:AsyncLoadingCache не поддерживает слабые и мягкие ссылки, а Caffeine.weakValues() и Caffeine.softValues() нельзя использовать вместе.

Запись на внешнее хранилище

Метод CacheWriter может записывать все данные в кэше третьей стороне, чтобы избежать потери данных при перезапуске службы.

Язык кода:javascript
копировать
LoadingCache<String, Object> cache = Caffeine.newBuilder()
    .writer(new CacheWriter<String, Object>() {
        @Override public void write(String key, Object value) {
            // Запись на внешнее хранилище
        }
        @Override public void delete(String key, Object value, RemovalCause cause) {
            // Удалить внешнее хранилище
        }
    })
    .build(key -> function(key));

статистика

Кофеин имеет встроенную функцию сбора данных,проходитьCaffeine.recordStats()метод,можно открытьданныесобирать。такCache.stats()метод将会返回когда前кэшнекоторые изстатистикаиндекс,Например:

  • hitRate:Запроскэшпроцент попаданий。
  • evictionCount:исключенкэшколичество。
  • averageLoadPenalty:新值被载入из平均耗час。
Язык кода:javascript
копировать
Cache<String, String> cache = Caffeine.newBuilder().recordStats().build();
cache.stats(); // Получить индикатор статистики

SpringBoot интегрирует Caffeine Cache

После знакомства с Caffeine Cache давайте познакомимся с тем, как плавно интегрировать Caffeine Cache в проект.

Без лишних слов, приступим к практике.

Сначала добавьте зависимости Maven для Spring Boot Starter Cache и Caffeine в файл pom.xml:

Язык кода:javascript
копировать
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
  <dependency>
       <groupId>com.github.ben-manes.caffeine</groupId>
       <artifactId>caffeine</artifactId>
       <version>3.1.1</version>
  </dependency>
</dependencies>

Во-вторых, создайте класс конфигурации и создайте компонент CacheManager:

Язык кода:javascript
копировать
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

@Configuration
@EnableCaching
public class CachingConfig {

    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(caffeineCacheBuilder());
        return cacheManager;
    }

    Caffeine<Object, Object> caffeineCacheBuilder() {
        return Caffeine.newBuilder()
                .initialCapacity(100)
                .maximumSize(500)
                .expireAfterAccess(10, TimeUnit.MINUTES)
                .weakKeys()
                .recordStats();
    }
}

Класс Caffeine использует шаблон построителя и имеет следующие параметры конфигурации:

  • initialCapacity:кэшначальная мощность。
  • maximumSize:настраиватькэш Максимальное количество записей。когдакэш达到这个大小час,Начнется очистка.
  • maximumWeight:настраиватькэш Максимальный вес。需要同час定义一个Weigher<K,V>Как рассчитатькэш Вес записи。
  • weigher:определяет, как рассчитать каждыйкэш Вес записи。
  • expireAfterAccess:настраиватьсуществовать特定час间段后访问кэш После пункта,приведет к истечению его срока действия.
  • expireAfterWrite:настраиватьсуществовать特定час间段后写入(или изменить)кэш После пункта,приведет к истечению его срока действия.
  • Этот метод определяет определенный период времени после записи элемента кэша, по истечении которого элемент кэша будет обновляться асинхронно.
  • refreshAfterWrite:此метод定义了写入кэш После пунктаиз特定час间段,После этого элемент будет обновлен.
  • weakKeys:настраиватькэшkeyдляслабая ссылка,существовать GC можно устранить напрямую.
  • weakValues:настраиватьvalueдляслабая ссылка,существовать GC можно устранить напрямую.
  • softValues:настраиватькэшvalueдлямягкая ссылка, это можно устранить непосредственно до переполнения памяти.
  • recordStats:давать возможностькэшизстатистикаданные,Например, процент попаданий и т. д.
  • removalListener:настраиватькэш Удалить слушателей。когдакэшсерединаиз某个条目被移除час会被вызов。Может использоваться для записи журналов、Запустить действие.

Помимо настройки bean-компонентов, вы также можете использовать файлы конфигурации:

Язык кода:javascript
копировать
spring:
  cache:
    type: caffeine
    cache-names:
    - userCache
    caffeine:
      spec: maximumSize=1024,refreshAfterWrite=60s

После завершения настройки вы можете использовать его напрямую с аннотациями:

Язык кода:javascript
копировать
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class SomeService {

    @Autowired
    private SomeRepository someRepository;

    @Cacheable("items")
    public Item getItem(int id) {
        return someRepository.findById(id);
    }
}

В этом примере,Мы добавили @Cacheableаннотацию в метод getItem.,Каждый раз, когда этот метод вызывается,SpringСначала найди имяitemизcacheсерединаданет Есть перепискаidиз条目。если есть,Просто верните значение кэша,нет вызывает метод и сохраняет результат в кеше.

Как использовать аннотации

Как использовать аннотации,相关из常用аннотациявключать:

  • @Cacheable:表示该метод支持кэш。когдавызов被аннотацияизметодчас,Если соответствующий ключ уже существует кэш,Тело метода больше не будет выполняться,И возврат прямо из кэша. Когда метод возвращает ноль,Никакие кэш-операции выполняться не будут.
  • @CachePut:表示执行该метод后,其值将как最新结果возобновлять到кэшсередина。Этот метод будет выполняться каждый раз
  • @CacheEvict:表示执行该метод后,Запустит операцию очистки кэша.
  • @Caching:используется для объединения первых треханнотация,Например:
Язык кода:javascript
копировать
@Caching(cacheable = @Cacheable("users"),
         evict = {@CacheEvict("cache2"), @CacheEvict(value = "cache3", allEntries = true)})
public User find(Integer id) {
    return null;
}

Этот тип аннотации также можно использовать в классе, указывая, что все методы класса поддерживают соответствующую аннотацию кэша.

Среди них наиболее часто используемым является @Cacheable. Часто используемые атрибуты аннотации @Cacheable следующие:

  • cacheNames/value:кэш组件из名字,То есть имя кэша в cacheManager.
  • key:кэшданныечас使用изkey。默认使用метод参数值,Его также можно записать с использованием выражений SpEL.
  • keyGenerator:иkeyВыберите один для использования。
  • cacheManager:指定使用изкэш Менеджер。
  • condition:существоватьметод执行开始前检查,При условии, что,Осуществить кэш.
  • unless:существоватьметод执行Заканчивать后检查,В случае, если,Нет Осуществить кэш.
  • sync:данет Использовать режим синхронизации。若Использовать режим синхронизации,Когда несколько файлов загружают ключ одновременно,Остальные нить будут заблокированы.

Spring Cache также поддерживает выражения Spring Expression Language (SpEL). Вставлять динамические значения в имена или ключи кэша можно через SpEL.

Приведу несколько примеров:

Язык кода:javascript
копировать
@Cacheable(value = "books", key = "#isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

Он будет использовать переданный findBook методический isbn Значение параметра.

Вы также можете использовать более сложные выражения SpEL, например:

Язык кода:javascript
копировать
@Cacheable(value = "books", key = "#root.args[0]")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

#root.args[0] Относится к первому параметру вызова метода, т.е. isbn

Также есть примеры, содержащие условные выражения:

Язык кода:javascript
копировать
@Cacheable(value = "books", key = "#isbn", condition = "#checkWarehouse == true")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

только если checkWarehouse Параметры true кеш будет применен.

Режим синхронизации кэша

@Cacheable默认из行для模式да Нет同步из。这意味着如果你существовать多нить环境середина使用它,и есть два или более нит, запрашивающих одни и те же данные одновременно,Тогда может произойти поломка кэша. То есть, да,Все запросы попадают в библиотеку данных,Потому что до того, как первый запрос заполнит кэш,Все остальные запросы не найдут элемент кэша.

Spring 4.1Появился новый объект недвижимостиsyncрешить эту проблему。如果настраивать@Cacheable(sync=true),тогда только один нить выполнит метод и добавит результат в кэш,Другая нить подождет.

Вот пример кода:

Язык кода:javascript
копировать
@Service
public class BookService {

    @Cacheable(cacheNames="books", sync=true)
    public Book findBook(ISBN isbn) {
        // Вот несколько медленных способов поиска книг, таких как запросы к библиотеке данных, вызовы API и т. д.
    }
}

В этом примере,Независимо от того, сколько людей пытаются найти одну и ту же книгу, используя один и тот же ISBN.,только одиннитьдействительно будет реализованоfindBookметод并将结果存储существовать名для"books"изкэшсередина。другойнитьбуду ждать,Затем получите результат из кэша,而Нет需要执行findBookметод。

В разных конфигурациях Caffeine режим синхронизации ведет себя по-разному:

Тип кэша кофеина

Включить ли синхронизацию

Многопоточное чтение несуществующих/вытесненных ключей

Многопоточное чтение ключей, подлежащих обновлению

Cache

нет

Каждый выполняет аннотированный метод независимо.

-

Cache

да

Поток 1 выполняет аннотированный метод, а поток 2 блокируется до завершения обновления кэша.

-

LoadingCache

нет

Поток 1 выполняет функцию load(), а поток 2 блокируется до завершения обновления кэша.

Поток 1 немедленно возвращает значение, используя старое значение, и асинхронно обновляет кэшированное значение. Поток 2 возвращает значение немедленно, не обновляя его.

LoadingCache

да

Поток 1 выполняет аннотированный метод, а поток 2 блокируется до завершения обновления кэша.

Поток 1 немедленно возвращает значение, используя старое значение, и асинхронно обновляет кэшированное значение. Поток 2 возвращает значение немедленно, не обновляя его.

Содержание этой статьи подошло к концу. Наконец, я подведу краткое резюме. Надеюсь, эта статья принесет вам пользу и мысли.

В этой статье мы углубимся в кофеин. Кэш и его алгоритм Внутренняя работа исключения. Мы также подробно рассказываем, как интегрировать Caffeine в приложение SpringBoot. Кэш. Я надеюсь, что благодаря этой статье читатели смогут получить более глубокое представление о кофеине. Преимущества Cache и эффективное применение на практике.

В целом, Caffeine Cache не только предоставляет мощные функции кэширования, но и эффективную стратегию устранения. Это делает его очень хорошим выбором при работе с большими объемами данных или большим количеством одновременных запросов. Более того, благодаря хорошей совместимости со SpringBoot, вы можете быстро и легко использовать его в проектах SpringBoot.

Наконец, нам нужно помнить, что хотя кофеин Cache — мощный инструмент, но для правильного и эффективного использования требуется его алгоритм. имеет глубокое понимание. Поэтому рекомендуется продолжать уделять внимание и изучите последние достижения в этой области, чтобы лучше использовать кофеин. Кэш повышает производительность вашего приложения.

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose