Application practice of local caching Ehcache

0 23
Java local caching includes multiple frameworks, among which the commonly used o...

Java local caching includes multiple frameworks, among which the commonly used ones include: Caffeine, Guava Cache, and Ehcache. Among them, Caffeine is号称the king of local caching and has been highly praised by many programmers in recent years, and it is also the built-in local caching implementation of SpringBoot. However, in addition to Caffeine, there is another excellent local caching framework, Ehcache, which has the characteristics of speed and flexibility, supports memory and disk caching, and provides a wealth of configuration options and caching strategies. Let's take a look at Ehcache next.

First, EhcacheWhat is it

Ehcache is an open-source Java local caching framework that provides a fast and flexible caching solution. Ehcache supports memory and disk caching and can be integrated with various Java applications, including those based on the Spring framework. It provides rich configuration options and caching strategies to help developers improve the performance and response speed of their applications. Ehcache also supports distributed caching and can be integrated with other caching systems, such as the Terracotta cluster.

Second, Ehcache features

Application practice of local caching Ehcache

1、 Hierarchical storage:

On-heap storage: Use Java's on-heap RAM memory to store cache data. This layer uses the same heap memory as the Java application, and all this memory is scanned by the JVM garbage collector (GC). The more heap space JVM uses, the greater the impact of garbage collection pauses on application performance. This storage is very fast, but usually resource-limited.

Off-heap storage: Size is limited by the available RAM. It is not affected by Java garbage collection (GC). It is quite fast, but slower than heap storage because data must be moved in and out of the JVM heap when storing and re-accessing data.

Disk storage: Use disk (file system) to store cache data. This type of storage resource is usually very abundant, but it is slower than storage based on RAM. It is recommended to use fast and dedicated SSD disks to optimize throughput for all applications that use disk storage.

Cluster storage (distributed): This data storage is a cache on the remote server. Due to network latency and factors such as establishing client/server consistency, cluster storage brings additional performance损耗, and the performance will be lower.

2、 Flexible expiration time:

No expiration:The cache mapping will never expire as long as the application exists;

Lifetime:The cache mapping will expire after a fixed time since creation;

Idle time:The cache mapping will expire after a fixed duration since the last access;

Custom expiration time:Implement personalized expiration judgment through the overloading of the ExpiryPolicy interface;

The interface is as follows:

Return value definition:

Duration.ZERO: Indicates immediate expiration

Duration.INFINITE: The mapping never expires

Duration.set specific time: The item expires after the corresponding time is set

Duration.set time period: The item expires after the corresponding period is set

Duration.set to null: The previous expiration time remains unchanged

3. Eviction Policy

LFU:Cache淘汰 with low access frequency.

LRU:Based on the most recent access time for淘汰.

FIFO:The data item enters the cache first is used for淘汰.

Three, cache principle

Taking three layers as an example: heap memory, off-heap storage, local disk storage.

Architecture diagram:

Description: cache-manager, cache, element are the core of Ehcache local cache, ensuring consistency between layers through transactional operations of data writing. At the same time, based on storage change listeners, clean up the changed data and data that meets the淘汰 strategy, or persist it to local disk;

Flowchart (based on source code):

To be supplemented

Four, practical application

1. pom introduction:

<dependency>    
  <groupId>org.ehcache</groupId>    
  <artifactId>ehcache</artifactId>    
  <version>3.10.0</version>
</dependency>
<dependency>    
  <groupId>javax.cache</groupId>    
  <artifactId>cache-api</artifactId>
</dependency>

2. Create an instance:

/*************************** 1. Pure memory operation *****************************/
    // 1.1 Create cache preConfigured based on memory
    CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
            .withCache("preConfigured",
                    CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)))
            .build(true);

    // 1.2 Get cache instance
    Cache<Long, String> preConfigured = cacheManager.getCache("preConfigured", Long.class, String.class);

    /*************************** 2. Add instance *****************************/
    // 2.1 Create a new instance and get the instance
    Cache<Long, String> myCache = cacheManager.createCache("myCache",
            CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)))

    /*************************** 3. Three-tier storage - Persistent disk *****************************/
    // 3.1 Create cache myData based on Memory->Off-heap Storage->Local Disk
    PersistentCacheManager persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder()
            .with(CacheManagerBuilder.persistence(new File("/home/export/App/conf/", "myData")))
            .withCache("threeTieredCache",
                    CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
                            ResourcePoolsBuilder.newResourcePoolsBuilder()
                                    .heap(10, EntryUnit.ENTRIES)
                                    .offheap(1, MemoryUnit.MB)
                                    .disk(20, MemoryUnit.MB, true)
                    )
            ).build(true);

    // 3.2 Obtain the storage instance threeTieredCache
    Cache<Long, String> threeTieredCache = persistentCacheManager.getCache("threeTieredCache", Long.class, String.class);

    /*************************** 4. A manager manages multiple caches - Persistent disk *****************************/
    // 4.1 An instance manages multiple caches and each cache can be persisted to local disk
    PersistentCacheManager persistentCacheManager1 = CacheManagerBuilder.newCacheManagerBuilder()
            .with(CacheManagerBuilder.persistence(
                    new File("/path/to/persistent/directory1").getAbsoluteFile()))
            .withCache("cache1",
                    CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
                            ResourcePoolsBuilder.newResourcePoolsBuilder()
                                    .heap(10, EntryUnit.ENTRIES)
                                    .offheap(1, MemoryUnit.MB)
                                    .disk(20, MemoryUnit.MB, true)
                    )
            )
            .with(CacheManagerBuilder.persistence(
                    new File("/path/to/persistent/directory2").getAbsoluteFile()))
            .withCache("cache2",
                    CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, Integer.class,
                            ResourcePoolsBuilder.newResourcePoolsBuilder()
                                    .heap(20, EntryUnit.ENTRIES)
                                    .offheap(2, MemoryUnit.MB)
                                    .disk(30, MemoryUnit.MB, true)
                    )
            )
            .build(true);

Description:

a. There are many methods for common cache instances mentioned above, among which the first one is pure memory operation, and the third one is a three-tier storage and persistent disk instance. The following is a test and verification based on the third method;

Daily applications can be used in combination, for example:

• Heap memory + off-heap storage + local disk

• Heap memory + off-heap storage

• Heap memory + local disk

b. If local disk storage is selected (it is necessary to use persistentCacheManager.close(); to release resources before the system exits to ensure the accuracy of disk data), the subsequent system restart will load the data in the disk to the cache, so that the cache remains valid within the effective period, which can reduce the pressure on the backend DB during application startup;

3. Test cases

4. Results:

Persistent disk:

5. Conclusion:

Cache + disk test is OK;

Data with validity period is not returned after expiration;

The system restart loads disk data normally;

Other notes:

Ehcache can be combined with the Terracotta plugin to implement distributed storage. Those who are interested in this part can discuss together. However, for online systems, if distributed storage is required, it is recommended to use redis directly. The distributed implementation of Ehcache is not reliable, the core still adopts the broadcast cluster mode to achieve data synchronization and update, and its performance is affected by machine IO, disk, network, etc., and it will not be better than redis in practical application cases.

6. The following is the completed test code

package com.jx.jxreserve.groupbuy.manager;

import com.jd.flash.commons.exception.BaseBusinessException;
import com.jx.jxreserve.groupbuy.common.enums.ErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.PersistentCacheManager;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ExpiryPolicyBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.units.EntryUnit;
import org.ehcache.config.units.MemoryUnit;
import org.springframework.stereotype.Component;

import java.io.File;
import java.time.Duration;

import static org.ehcache.Status.AVAILABLE;

*/
 * @author zhangpengfei9
 * @version V1.0
 * Test management class for Ehcache
 */
@Slf4j
@Component
public class EhcacheTestManager {

    /*************************** 1. Pure memory operation *****************************/
    // 1.1 Create cache preConfigured based on memory
    CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
            .withCache("preConfigured",
                    CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)))
            .build(true);

    // 1.2 Get cache instance
    Cache<Long, String> preConfigured = cacheManager.getCache("preConfigured", Long.class, String.class);

    /*************************** 2. Add instance *****************************/
    // 2.1 Create a new instance and get the instance
    Cache<Long, String> myCache = cacheManager.createCache("myCache",
            CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)))

    /*************************** 3. Three-tier Storage *****************************/
    // 3.1 Create cache myData based on Memory->Off-heap Storage->Local Disk
    PersistentCacheManager persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder()
            .with(CacheManagerBuilder.persistence(new File("/home/export/App/conf/", "groupData")))
            .withCache("testDiskCache",
                    CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
                                    ResourcePoolsBuilder.newResourcePoolsBuilder()
                                            .heap(10, EntryUnit.ENTRIES)
                                            .offheap(1, MemoryUnit.MB)
                                            .disk(20, MemoryUnit.MB, true)
                            )
                            .withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(600))) // Set cache expiration time
            ).build(true);


    /*************************** 4. Multiple Caches - Three-tier Storage *****************************/
    // 4.1 An instance manages multiple caches and each cache can be persisted to local disk
    PersistentCacheManager persistentCacheManager1 = CacheManagerBuilder.newCacheManagerBuilder()
            .with(CacheManagerBuilder.persistence(
                    new File("/home/export/App/conf/").getAbsoluteFile()))
            .withCache("cache1",
                    CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
                            ResourcePoolsBuilder.newResourcePoolsBuilder()
                                    .heap(10, EntryUnit.ENTRIES)
                                    .offheap(1, MemoryUnit.MB)
                                    .disk(20, MemoryUnit.MB, true)
                    )
            )
            .with(CacheManagerBuilder.persistence(
                    new File("/home/export/App/conf/").getAbsoluteFile()))
            .withCache("cache2",
                    CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, Integer.class,
                            ResourcePoolsBuilder.newResourcePoolsBuilder()
                                    .heap(20, EntryUnit.ENTRIES)
                                    .offheap(2, MemoryUnit.MB)
                                    .disk(30, MemoryUnit.MB, true)
                    )
            )
            .build(true);

    */
     /* Set the cache
     */
    public void setEhCache(Long key, String values) throws BaseBusinessException {
        try {
            // Get the storage instance threeTieredCache
            log.info("setEhCache.value:{},{}", values, key);
            Cache<Long, String> testDiskCache = getManagerCache("testDiskCache");

            testDiskCache.put(key, values);


        } catch (Exception e) {
            log.error("setEhCache failure! Exception:", e);
            throw new BaseBusinessException(ErrorCode.SYSTEM_DB_ERROR.getCode(), ErrorCode.SYSTEM_DB_ERROR.getMessage());
        }
    }

    */
     /* Query the cache
     */
    public String getEhCache(Long key) throws BaseBusinessException {
        try {
            // Get the storage instance threeTieredCache
            log.info("getEhCache.key:{}", key);
            Cache<Long, String> testDiskCache = getManagerCache("testDiskCache");
            return testDiskCache.get(key);
            

        } catch (Exception e) {
            log.error("setEhCache failure! Exception:", e);
            throw new BaseBusinessException(ErrorCode.SYSTEM_DB_ERROR.getCode(), ErrorCode.SYSTEM_DB_ERROR.getMessage());
        }
    }

    */
     /* Set the cache
     */
    public void closeEhCache() throws BaseBusinessException {
        try {
            // Get the storage instance threeTieredCache
            log.info("closeEhCache.persistentCacheManager.close1:{}", persistentCacheManager.getStatus());
            persistentCacheManager.close();
            log.info("closeEhCache.persistentCacheManager.close2:{}", persistentCacheManager.getStatus());
        } catch (Exception e) {
            log.error("setEhCache failure! Exception:", e);
            throw new BaseBusinessException(ErrorCode.SYSTEM_DB_ERROR.getCode(), ErrorCode.SYSTEM_DB_ERROR.getMessage());
        }
    }

    private Cache<Long, String> getManagerCache(String cache) {}}
        // 3.1 Create cache myData based on Memory->Off-heap Storage->Local Disk
        log.info("persistentCacheManager.getStatus():{}", persistentCacheManager.getStatus());
        if (AVAILABLE != persistentCacheManager.getStatus()) {
            persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder()
                    .with(CacheManagerBuilder.persistence(new File("/home/export/App/conf/", "groupData")))
                    .withCache("testDiskCache",
                            CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
                                    ResourcePoolsBuilder.newResourcePoolsBuilder()
                                            .heap(10, EntryUnit.ENTRIES)
                                            .offheap(1, MemoryUnit.MB)
                                            .disk(20, MemoryUnit.MB, true)
                            )
                    ).build(true);
            log.info("persistentCacheManager.getStatus1:{}", persistentCacheManager.getStatus());
        }

        Cache<Long, String> testDiskCache = persistentCacheManager.getCache(cache, Long.class, String.class);
        return testDiskCache;
    }
}


Author: Zhang Pengfei, JD Retail

Source: JD Cloud Developer Community. Please indicate the source when转载.

你可能想看:
最后修改时间:
admin
上一篇 2025年03月27日 06:36
下一篇 2025年03月27日 06:58

评论已关闭