Introduction to Java cache (coffeine, ehcache)

Caffeine

A high-performance cache library, Caffeine uses the Window TinyLfu recycling strategy to provide a near optimal hit rate.

rely on

maven

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

Grade

compile 'com.github.ben-manes.caffeine:caffeine:2.5.5'

Basic Usage

		@Test
    public void baseTest() {
        Cache<String, Data> cache = Caffeine.newBuilder()
            // Set expiration time
            .expireAfterWrite(1, TimeUnit.MINUTES)
            // Number of caches
            .maximumSize(100).build();
        // Set to cache 
        cache.put("A", new Data("A"));
        Assert.assertEquals(cache.getIfPresent("A").getData(), "A");
        // If the value exists, null will be returned if it does not exist
        Data b = cache.getIfPresent("B");
        Assert.assertNull(b);
        // If the value does not exist, it will be calculated and returned later
        b = cache.get("B", k -> new Data(k));
        Assert.assertEquals(cache.getIfPresent("B").getData(), "B");
        // Remove key manually
        cache.invalidate("A");
        Assert.assertNull(cache.getIfPresent("A"));
    }

Synchronous loading

		@Test
    public void syncLoadTest() {
        LoadingCache<String, Data> cache = Caffeine.newBuilder()
                .maximumSize(100)
                .expireAfterWrite(1, TimeUnit.MINUTES)
                .build(k -> new Data(k));
        //The obtained is still empty
        Assert.assertNull(cache.getIfPresent("A"));
        // get() retrieves the value. Here, value will be initialized according to the method specified during initialization
        Data a = cache.get("a");
        Assert.assertNotNull(a);
        Assert.assertEquals(a.getData(),"a");
    }

Asynchronous loading

		@Test
    public void asyncLoadTest() {
        AsyncLoadingCache<String, Data> cache = Caffeine.newBuilder().maximumSize(100).expireAfterWrite(1, TimeUnit.MINUTES).buildAsync(k -> new Data(k));
        cache.get("A").thenAccept(data -> {
            Assert.assertNotNull(data);
            Assert.assertEquals(data.getData(), "a");
        });
    }

The three loading methods use different Cache classes. You can choose an appropriate way to load data according to your own needs

Recycling strategy

  1. Based on the size set by maximumSize(), if the maximum value is exceeded, it will be collected asynchronously

  2. Delete elements based on weight size

    1. . maximumWeight(): Specifies the maximum capacity of the cache. When the cache exceeds this capacity, it will be used Window TinyLfu policy To delete the cache
    2. . weight ((k, V) - > {}): calculation method of weight
    3. maximumWeight and maximumSize cannot be used at the same time.
  3. Time based recycling

    1. Expire after access - an entry expires after the last read or write occurred
    2. Expire after write - entries expire after the last write
    3. Custom policy - expiration time is calculated independently by Expiry
  4. Reference based

    We can configure the eviction of the cache to be based on the garbage collector. For this purpose, we can configure key and value as weak references or only value as soft references.

    • Caffeine.weakKeys(): use weak references to store keys. If there is no strong reference to the key elsewhere, the cache will be recycled by the garbage collector.
    • Caffeine.weakValues(): use weak references to store value.
    • Caffeine.softValues(): use soft references to store value. When the memory is full, soft referenced objects will be garbage collected in a least recently used manner.

Ehcache

Ehcache has developed from Hibernate and gradually covered all functions of Cahce. It is a project with the best development momentum at present. It has the characteristics of fast, simple, low consumption, small dependence, strong scalability, supporting object or serialization cache, supporting cache or element failure, providing LRU, LFU and FIFO cache strategies, supporting memory cache and disk cache, distributed cache mechanism and so on.

function

  • Support memory and disk storage
  • Multiple caching strategies
  • Support multiple cache manager instances and multiple cache areas of an instance

Cache elimination strategy

  • FIFO: first in first out
  • LFU: least used. The cached element has a hit attribute. The element with the lowest hit value will be cleared out of the cache
  • LRU: least used recently. The cached element has a timestamp. When the cache capacity is full and it needs to make room for caching new elements, the element with the farthest timestamp from the current time in the existing cache element will be cleared out of the cache

rely on

maven 
<dependency>
      <groupId>org.ehcache</groupId>
      <artifactId>ehcache</artifactId>
      <version>3.7.0</version>
</dependency>
gradle
compile 'org.ehcache:ehchache:3.7.0'

Basic Usage

public class EhCache implements LocalCache<String, Data> {
    private CacheManager        cacheManager;
    private Cache<String, Data> cache;
    public EhCache() {
        // Create a cache manager. A cache manager can associate multiple caches
        cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build();
        // initialization
        cacheManager.init();
        // Create dataCache cache
        CacheConfigurationBuilder builder = CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, Data.class, ResourcePoolsBuilder.heap(100));
        cache = cacheManager.createCache("dataCache", builder);
    }
    @Override
    public Data get(String K) {
        return cache.get(K);
    }
    @Override
    public void set(String K, Data data) {
        cache.put(K, data);
    }
}

Comparison of two caching frameworks

characteristic

In terms of supported functions, ehcache supports more functions and features, such as multi-level cache, distributed cache, cache listener and so on. However, if you just want to simply use a memory cache component and have high performance requirements, you can give priority to Caffeine. Its performance is better than ehcache, and it uses a better cache elimination strategy to provide a near ideal hit rate. It has been used as a basic cache component in spring 5.

Ease of use

In terms of my simple use, Caffeine provides a more friendly api, and ehcache does not seem to provide asynchronous loading. The configuration is also a little cumbersome.

performance

1. Read more and write less

Test conditions

1. Cache 1000 data

2.8 threads read and 2 threads write

Caffeine (read / write)Ehcache (read / write)
11558360022/1847731561794188434/155912462
21861119523/2884436761818122432/147250831
31421957913/2778566681348268819/142143289
average1613812486/2503578331653526561/148435527
2 read only scenario

Test conditions

1. Cache 1000 data

2.10 thread reads

Caffeine (read)Ehcache (read)
117236282252129962082
218990308852025097805
321246126642086497546
average19157572582080519144

In the read-only scenario, the performance of Caffeine is slightly worse than that of Ehcache.

summary

There is little difference between the two in read performance, but Caffeine is significantly higher than Ehcache in write performance. In terms of ease of use and performance, I think Caffeine is enough for general projects.

Tags: Ehcache Cache

Posted by john_bboy7 on Fri, 01 Apr 2022 12:18:49 +0300