Major manufacturers are using EhCache. Where is it better than Redis?

Posted by unlishema.wolf on Wed, 15 Dec 2021 18:38:32 +0100

Story background

With the decline of hardware price, people rely more and more on hardware. I even heard that the code is not important. If not, add machines. For example, the use of cache is usually based on virtual machine memory, disk storage and Middleware (Redis memory). We all know that the most suitable is the best, but in practice, it is often directly available to Redis.

So, is Redis the best choice? Not to mention the memory requirements, it may not be the best in terms of efficiency and performance. Therefore, using different caching strategies in different scenarios is what experts should pursue.

This article introduces you to another caching framework besides Redis: EhCache. The reason why I want to write is also because I used this framework in the project and encountered some problems, so I decided to study it in depth. After the study, it was really interesting~

Introduction to EhCache

EhCache is a pure Java in-process caching framework, which is fast and lean. Note that for the keyword process here, the process based cache intuition tells us that the efficiency must be higher, because it operates directly within the process, but there may be problems with cache sharing between different applications.

EhCache is the default CacheProvider in Hibernate, which is also supported by Spring Boot. The cache abstraction provided in Spring also supports binding to the EhCache caching framework, and supports annotation based use. Therefore, EhCache is a widely used Java based cache framework, which is also very convenient to use.

EhCache provides a variety of cache strategies, mainly divided into memory and disk levels. It is a cache framework for general cache, Java EE and lightweight containers.

Features of EhCache

Briefly describe the characteristics of the framework:

  • Simple and fast, with a variety of caching strategies;
  • There are two levels of cached data: memory and disk. There is no need to worry about capacity;
  • Cache data will be written to disk during virtual machine restart;
  • Distributed caching can be implemented through RMI and pluggable API;
  • Listening interface with cache and cache manager;
  • Support multiple cache manager instances and multiple cache areas of an instance, and provide Hibernate cache implementation;

EhCache can be used alone, but it is usually used in combination with three-party class libraries such as Mybatis and Shiro. EhCache is used in combination with Shiro in my project.

In addition to its advantages, EhCache also has some disadvantages. For example, it takes up a lot of disk space because the algorithm of DiskCache is simple and only adds storage directly to elements. Although this can improve efficiency, the disk will soon be full in a frequently used system.

In addition, data security cannot be guaranteed. Of course, conflicts may occur when Java processes are suddenly kill ed. The method of EhCache conflict resolution is to rebuild the cache, which may affect the cache data when it needs to be maintained. Cache is only a simple acceleration and cannot guarantee the security of data.

EhCache and Redis

EhCache caches directly in the JVM, which is fast and efficient. Compared with Redis, the operation is simple, easy to use and efficient. Although EhCache also provides a cache sharing scheme, it does not support distributed clusters very well, and the implementation of cache sharing is troublesome.

Redis accesses the cache service through the Socket, which is less efficient than EhCache and much faster than the database. It is convenient to process cluster and distributed cache, and has a mature scheme.

Therefore, if it is a single application or has high requirements for cache access, EhCache can be considered; Redis is recommended for large-scale systems with cache sharing, distributed deployment and large cache content.

EhCache architecture diagram

Take a look at the architecture diagram of EhCache and see how it consists of several parts.

The Cache Replication section provides a Cache Replication mechanism for distributed environments. EhCache was originally an independent local cache framework component. In later development, combined with Terracotta service array model, it can support distributed cache clusters, mainly including RMI, JGroups, JMS and Cache Server for inter node communication.

In process APIs provides support based on JSR, JMX and other standards, which can be well compatible and transplanted. At the same time, it has a perfect monitoring and management mechanism for all kinds of objects.

Network APIs provides external support based on RESTful API, JMS API and Cache Server.

In the process of use, the Core part that needs attention is the middle Core part. It contains Core API s and concepts:

  • CacheManager: cache manager, which can be created by single instance or multiple instances. It is also the entry class of Ehcache.
  • Cache: each CacheManager can manage multiple caches, and each cache can manage multiple elements in the way of hash. All caches implement the Ehcache interface;
  • Element: the constituent unit of a single piece of cached data, which is used to store the real cached content.

The management of the three can be represented by the following figure:

Cache expiration policy

Memory store algorithms such as Memory Store LRU, Memory Store LFU and Memory Store FIFO can also be seen in the architecture diagram. That is, when the cache occupancy is close to the critical value, the above elimination strategy will be used to clean up some data.

EhCache provides three elimination algorithms:

  • FIFO: First In First Out. Judge the storage time, and the data farthest from the current will be eliminated first.
  • LRU: Least Recently Used. Judge the time of recent use, and the farthest data at present will be eliminated first.
  • LFU: Least Frequently Used. In a period of time, the data that is used the least times will be eliminated first.

Ehcache adopts the lazy elimination mechanism. Each time data is put into the cache, a time will be saved. When reading, TTL will be compared with the set time to judge whether it is expired.

EhCache actual combat analysis

After understanding the above basic knowledge, let's experiment with how to use EhCache. Where EhCache2 X and EhCache3 There is a big gap in the use of X.

The relatively new 3.9.1 is adopted here 6. Different versions have different API usage.

Using EhCache based on API

EhCache provides two ways to create CacheManger and Cache based on API and xml. Let's first look at the API based form:

Introduce EhCache dependency in pom file:

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

The code created and used is as follows:

public class EhCacheTest {

    @Test
    public void test() {
        // 1. First create a CacheManagerBuilder;
        // 2. Use CacheManagerBuilder to create a pre configured Cache: the first parameter is an alias, and the second parameter is used to configure the Cache;
        // 3. Build method to build and initialize; The true parameter in build indicates initialization.
        CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
                .withCache("preConfigured",
                        CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
                                ResourcePoolsBuilder.heap(100)).build())
                .build(true);

        // Retrieve the pre configured. For key and value value types, it is required to be type safe, otherwise ClassCastException will be thrown.
        Cache<Long, String> preConfigured = cacheManager.getCache("preConfigured", Long.class, String.class);

        System.out.println("Get from cache key by preConfigured: " + preConfigured);

        // Create a new Cache through the CacheManager according to the requirements. Instantiated and fully instantiated caches will be through CacheManager Getcache API returns.
        Cache<Long, String> myCache = cacheManager.createCache("myCache",
                CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
                        ResourcePoolsBuilder.heap(100)).build());
        // Use the put method to store data
        myCache.put(1L, "da one!");
        // Get data using get method
        String value = myCache.get(1L);
        System.out.println("Get from cache key Is 1 L: " + value);
        // The close method frees the cache resources managed by the CacheManager
        cacheManager.close();
    }
}

The above code demonstrates how to create CacheManager and Cache, set and obtain Cache based on API.

Using EhCache based on XML

The dependency Jar package remains unchanged. Create the configuration file ehcache. Exe in the src/main/resources / directory xml.

<config
        xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
        xmlns='http://www.ehcache.org/v3'
        xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd">

    <cache alias="foo">
        <key-type>java.lang.String</key-type>
        <value-type>java.lang.String</value-type>
        <resources>
            <heap unit="entries">20</heap>
            <offheap unit="MB">10</offheap>
        </resources>
    </cache>

    <cache-template name="myDefaults">
        <key-type>java.lang.Long</key-type>
        <value-type>java.lang.String</value-type>
        <heap unit="entries">200</heap>
    </cache-template>

    <cache alias="bar" uses-template="myDefaults">
        <key-type>java.lang.Number</key-type>
    </cache>

    <cache alias="simpleCache" uses-template="myDefaults" />

</config>

3.x version and 2 The X version is different, which is very obvious in the xml configuration file. In 2.x, the ehcache element is the root node, while 3 X takes config as the root node.

The above xml contains three parts:

  • Normal cache foo: the cache alias is foo, and the key value type of the cache is String. If not specified, the default is the Object type.
  • Cache template: implement a configuration abstraction so that it can be extended in the future;
  • Cache bar based on cache template: the cache template myDefaults is used and the key type type is overwritten. The key type of myDefaults is Long and becomes Number after overwriting;

Other attributes and elements in cache:

  • Name is the name;
  • Alias is an alias;
  • Key type is the type of key;
  • Value type is the type of value;
  • Heap specifies the format of entities that can be created in the heap, where unit="entries" indicates that the following 20 are entities;
  • offheap means that up to 10M heap memory can be allocated before starting to eliminate expired cache entries;
  • Uses template indicates the name of the template used;

Of course, you can also configure the directory of the cache through the persistence element. The use of other attributes can be explored slowly.

Using EhCache based on Spring Boot

As mentioned earlier, Spring supports caching, and Spring Boot also supports automatic configuration of caching. The following is to complete the EhCache integration and use case demonstration based on Spring Boot.

Introduce the corresponding starter in Spring Boot:

<!-- ehcache rely on-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>3.9.6</version>
</dependency>

In application Add the following configuration in properties:

spring.cache.ehcache.config=ehcache.xml

Add the @ EnableCaching annotation on the Spring Boot boot class:

@EnableCaching
@SpringBootApplication
@MapperScan("com.secbro.mapper")
public class SpringBootMainApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootMainApplication.class, args);
    }
}

Create a user cached entity class Person:

@Data
public class Person {

    public Person(int id,String name){
        this.id = id;
        this.name = name;
    }

    private int id;

    private String name;
}

Corresponding Service method implementation:

public interface PersonService {
    Person getById(int id);
}

@Slf4j
@Service("personService")
public class PersonServiceImpl implements PersonService {

    @Cacheable(value = "personCache", key = "#id")
    @Override
    public Person getById(int id) {
        log.info("query id={}User", id);
        if (id == 1) {
            return new Person(1, "Tom");
        } else if (id == 2) {
            return new Person(2, "Jim");
        }
        return new Person(3, "Other");
    }
}

The @ Cacheable annotation provided by Spring specifies that the name of the cache is personCache and the key is id. The log is printed inside the method. If it is called inside the method, it will be printed.

Write a unit test class:

@Slf4j
@SpringBootTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class PersonServiceTest {

    @Resource
    private PersonService personService;

    @org.junit.jupiter.api.Order(1)
    @Test
    void testCache() throws InterruptedException {
        log.info("1st query id=1 Data");
        personService.getById(1);
        log.info("2nd query id=1 Data");
        personService.getById(1);
        Thread.sleep(3000);
    }
}

Call the corresponding method twice and print the log as follows:

c.s.s.PersonServiceTest                  : 1st query id=1 Data
c.s.s.i.PersonServiceImpl                : query id=1 User
c.s.s.PersonServiceTest                  : 2nd query id=1 Data

You can see that the first time you enter the method for query, the second time you leave the cache.

There are many usage methods and scenarios for the use of cache annotations provided by Spring, which will not be expanded here.

Summary

Because the work happens to use this technology, I studied and wrote an article to take you through the basic knowledge, technical architecture, use scenarios, API use and Spring Boot based integration of EhCache. On the whole, it is at the entry level, and you can further learn and expand on this basis. As for the distributed support of EhCache, this paper does not cover it. The main reason is that it is not so easy to use. If you are interested, you can study it yourself.

About the blogger: the author of the technical book "inside of SpringBoot technology", loves to study technology and write technical dry goods articles.

The official account: "new horizon of procedures", the official account of bloggers, welcome the attention.

Technical exchange: please contact blogger wechat: zhuan2quan

Topics: Ehcache Redis Cache