Выбор технологии локального кэширования Java (Guava Cache, Caffeine, Encache)

Java

предисловие

Для бэкенд-разработчика Java, когда дело доходит до кэширования, первая реакция — это Redis и memcache. Использование этого типа кеша достаточно для решения большинства проблем с производительностью, и у Java есть очень зрелые API для обоих. Но нам также нужно знать, что они оба принадлежат удаленному кешу (распределенному кешу).Процесс приложения и кешированный процесс обычно распределены по разным серверам, и разные процессы общаются через RPC или HTTP. Преимущество такого типа кеша заключается в том, что кеш отделен от службы приложений и поддерживает хранение больших объемов данных.

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

В этой статье мы в основном обсуждаем некоторые распространенные решения локального кэша Java.

Общие методы локального кэширования

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

  • Самостоятельно реализованный локальный кеш на основе HashMap
  • Guava Cache
  • Caffeine
  • Encache

Соответственно вводятся:

1. Настроить локальный кеш на основе HashMap

Суть кеша — хранящаяся в памяти структура данных KV, которая соответствует HashMap в jdk.Однако для реализации кеша необходимо учитывать такие стратегии, как безопасность параллелизма и ограничения емкости.Нижеследующее кратко представляет способ для реализации кеша с помощью LinkedHashMap:

public class LRUCache extends LinkedHashMap {

    /**
     * 可重入读写锁,保证并发读写安全性
     */
    private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private Lock readLock = readWriteLock.readLock();
    private Lock writeLock = readWriteLock.writeLock();

    /**
     * 缓存大小限制
     */
    private int maxSize;

    public LRUCache(int maxSize) {
        super(maxSize + 1, 1.0f, true);
        this.maxSize = maxSize;
    }

    @Override
    public Object get(Object key) {
        readLock.lock();
        try {
            return super.get(key);
        } finally {
            readLock.unlock();
        }
    }

    @Override
    public Object put(Object key, Object value) {
        writeLock.lock();
        try {
            return super.put(key, value);
        } finally {
            writeLock.unlock();
        }
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry eldest) {
        return this.size() > maxSize;
    }
}

LinkedHashMap поддерживает структуру связанного списка, которая используется для хранения порядка вставки или порядка доступа узлов (выберите один из двух) и инкапсулирует внутри некоторую бизнес-логику.Ему нужно только переопределить метод removeEldestEntry для реализации кэшированной стратегии исключения LRU. Кроме того, мы используем блокировки чтения-записи, чтобы обеспечить параллельную безопасность кеша. Следует отметить, что этот пример не поддерживает стратегию исключения времени истечения срока действия.

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

2. Реализовать локальное кэширование на основе Guava Cache.

Guava – это основная библиотека расширений Java, исходный код которой открыт командой Google. Она включает наборы инструментов, такие как коллекции, примитивы параллелизма, кэширование, ввод-вывод и отражение. Она гарантирует производительность и стабильность и широко используется. Guava Cache поддерживает множество функций:

  • Поддержка максимальной емкости
  • Поддерживает две стратегии удаления с истекшим сроком действия (время вставки и время доступа)
  • Поддержка простых статистических функций
  • Реализация на основе алгоритма LRU

Использование Guava Cache очень просто.Во-первых, вам нужно ввести пакет maven:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>18.0</version>
</dependency>

Простой пример кода выглядит следующим образом:

public class GuavaCacheTest {

    public static void main(String[] args) throws Exception {
        //创建guava cache
        Cache<String, String> loadingCache = CacheBuilder.newBuilder()
                //cache的初始容量
                .initialCapacity(5)
                //cache最大缓存数
                .maximumSize(10)
                //设置写缓存后n秒钟过期
                .expireAfterWrite(17, TimeUnit.SECONDS)
                //设置读写缓存后n秒钟过期,实际很少用到,类似于expireAfterWrite
                //.expireAfterAccess(17, TimeUnit.SECONDS)
                .build();
        String key = "key";
        // 往缓存写数据
        loadingCache.put(key, "v");

        // 获取value的值,如果key不存在,调用collable方法获取value值加载到key中再返回
        String value = loadingCache.get(key, new Callable<String>() {
            @Override
            public String call() throws Exception {
                return getValueFromDB(key);
            }
        });

        // 删除key
        loadingCache.invalidate(key);
    }

    private static String getValueFromDB(String key) {
        return "v";
    }
}

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

3. Caffeine

Caffeine — это новое поколение инструментов кэширования, основанное на java8, и производительность кэширования близка к теоретическому оптимуму. Его можно рассматривать как расширенную версию Guava Cache. Функции у них схожие. Разница в том, что Caffeine использует алгоритм, сочетающий в себе преимущества LRU и LFU: W-TinyLFU, который имеет очевидные преимущества в производительности. Чтобы использовать Caffeine, вам сначала нужно установить пакет maven:

<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>2.5.5</version>
</dependency>

Использование в основном похоже на Guava Cache:

public class CaffeineCacheTest {

    public static void main(String[] args) throws Exception {
        //创建guava cache
        Cache<String, String> loadingCache = Caffeine.newBuilder()
                //cache的初始容量
                .initialCapacity(5)
                //cache最大缓存数
                .maximumSize(10)
                //设置写缓存后n秒钟过期
                .expireAfterWrite(17, TimeUnit.SECONDS)
                //设置读写缓存后n秒钟过期,实际很少用到,类似于expireAfterWrite
                //.expireAfterAccess(17, TimeUnit.SECONDS)
                .build();
        String key = "key";
        // 往缓存写数据
        loadingCache.put(key, "v");

        // 获取value的值,如果key不存在,获取value后再返回
        String value = loadingCache.get(key, CaffeineCacheTest::getValueFromDB);

        // 删除key
        loadingCache.invalidate(key);
    }

    private static String getValueFromDB(String key) {
        return "v";
    }
}

По сравнению с Guava Cache Caffeine имеет очевидные преимущества с точки зрения функциональности и производительности. В то же время их API похожи, и код, использующий Guava Cache, можно легко переключить на Caffeine, что снижает затраты на миграцию. Следует отметить, что SpringFramework5.0 (SpringBoot2.0) также отказался от схемы локального кэширования Guava Cache и вместо этого использовал Caffeine.

4. Encache

Encache — это среда внутрипроцессного кэширования на чистом языке Java с быстрыми, компактными и другими характеристиками.Это CacheProvider по умолчанию в Hibernate. По сравнению с Caffeine и Guava Cache, Encache обладает более богатыми функциями и большей масштабируемостью:

  • Поддерживает несколько алгоритмов удаления кеша, включая LRU, LFU и FIFO.
  • Кэш поддерживает три типа хранилища в куче, вне кучи и дисковое хранилище (поддерживает постоянство).
  • Поддержка различных кластерных решений для решения проблем с совместным использованием данных

Чтобы использовать Encache, вам сначала нужно импортировать пакет maven:

<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>3.8.0</version>
</dependency>

Вот простой вариант использования:

public class EncacheTest {

    public static void main(String[] args) throws Exception {
        // 声明一个cacheBuilder
        CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
                .withCache("encacheInstance", CacheConfigurationBuilder
                        //声明一个容量为20的堆内缓存
                        .newCacheConfigurationBuilder(String.class,String.class, ResourcePoolsBuilder.heap(20)))
                .build(true);
        // 获取Cache实例
        Cache<String,String> myCache =  cacheManager.getCache("encacheInstance", String.class, String.class);
        // 写缓存
        myCache.put("key","v");
        // 读缓存
        String value = myCache.get("key");
        // 移除换粗
        cacheManager.removeCache("myCache");
        cacheManager.close();
    }
}

Суммировать

  • С точки зрения простоты использования, Guava Cache, Caffeine и Encache имеют очень зрелые решения для доступа и просты в использовании.
  • С функциональной точки зрения Guava Cache и Caffeine имеют схожие функции, оба поддерживают только кеш в куче, тогда как Encache более функционален, чем
  • С точки зрения производительности, Caffeine — лучший, GuavaCache — второй, а Encache — худший (на следующем рисунке показаны результаты сравнения производительности трех).

img
В общем, для решения локального кэша автор рекомендует Caffeine, который намного опережает по производительности. Хотя Encache более функционален, и даже предоставляет функции персистентности и кластеризации, эти функции можно реализовать другими способами. В реальных бизнес-проектах рекомендуется использовать Caffeine в качестве локального кеша, а Redis или Memcache в качестве распределенного кеша для построения многоуровневой системы кеша для обеспечения производительности и надежности.