The use of JetCache- (Introductory Tutorial)

Article directory

foreword

I don’t produce knowledge, I’m just a porter of knowledge, the following are some of my experience sharing using spring-boot to integrate jetCache.

I. Overview

[github]:https://github.com/alibaba/jetcache

Official documentation: https://github.com/alibaba/jetcache/wiki/Home_CN

The official website describes JetCache as follows:

JetCache is a Java-based cache system package that provides a unified [API] and annotations to simplify the use of caches. JetCache provides more powerful annotations than SpringCache, can natively support TTL, two-level cache, distributed automatic refresh, and also provides an Cacheinterface for manual cache operations. There are currently four implementations, RedisCache, TairCache(this part is not open-sourced on github), CaffeineCache(in memory) and a simple one LinkedHashMapCache(in memory), and it is very simple to add new implementations.

All features:

  • Access the Cache system through a unified API
  • Implement declarative method caching through annotations, support TTL and two-level caching
  • Create and configure Cache instances through annotations
  • Automatic statistics for all Cache instances and method caches
  • Key generation strategy and Value serialization strategy are configurable
  • Distributed cache automatic refresh, distributed lock (2.2+)
  • Asynchronous Cache API (2.2+, when using Redis’ lettuce client)
  • Spring Boot support

jetCacheThe SpringCache is encapsulated, so the use of JetCache is very similar to the use of SpringCache. And jetCache implements multi-level caching, cache statistics, automatic star brushing, asynchronous calls, data reports and other functions based on the original functions.

jetCache sets up a multi-level caching solution for local caching and remote caching

  • local cache (local)
    • linkedHashMap
    • Caffeine
  • Remote cache (remote)
    • Redis
    • Three

The local cache is generally used linkedHashMap, and the remote cache is generally used Redis.

Function brief:

  1. There are two cache implementations: interface and api, the interface is easy to use, and the api is similar to map, which can control the cache in a finer-grained manner
    • @CreateCache
    • @Cached
  2. Automatic refresh strategy to prevent a certain cache from invalidating, suddenly increasing the number of visits, causing the database to hang (cache avalanche)
  3. There are loose distributed locks. For the same key, only one machine in the world automatically refreshes

2. Use steps

1. Introduce dependent coordinates

You can go to the [maven repository] to find the coordinates corresponding to jetCache, jetcacheand you can find it by searching directly.

Generally we choose JetCache Starter Redisthis coordinate.

Copy the coordinates and paste them into the project

<!-- https://mvnrepository.com/artifact/com.alicp.jetcache/jetcache-starter-redis -->
<dependency>
    <groupId>com.alicp.jetcache</groupId>
    <artifactId>jetcache-starter-redis</artifactId>
    <version>2.6.0</version>
</dependency>

2. Write the configuration file

As mentioned above, JetCache not only supports local local caching, but also supports remote caching.

The yml configuration is as follows: (refer to the official configuration instructions )

# jetCache Configure 
jetcache: 
  # Specify the statistics interval, in minutes, the default is 0: means no statistics 
  statIntervalMinutes:  15 
  # Whether areaName is used as the cache key prefix, the default is True 
  areaInCacheName:  false 
  # Local cache scheme 
  local: 
    # Area area name 
    default: 
      # Cache type, already supported optional: linkedhashmap, caffeine 
      type:  linkedhashmap 
      # The global configuration of the key converter, currently only: fastjson 
      keyConvertor:  fastjson 
      # The global configuration of the largest element of each cache instance, only the local type of cache needs to specify the 
      limit:  100 
      # jetCache2.2 and above, in milliseconds, specify how long there is no access to invalidate the cache, currently only supported by local cache. 0 means do not use this function 
      expireAfterAccessInMillis:  30000 
  # Remote caching scheme 
  remote: 
    # Area area name 
    default:
      # Cache type, optional: redis, tail 
      type:  redis 
      # global configuration of key converter, currently only: fastjson 
      keyConvertor:  fastjson 
      # global configuration of serializer. Only remote type caches need to be specified, optional java and kryo 
      valueEncoder:  java 
      valueDecoder:  java 
      # redis ip address 
      host:  127.0 .0 .1 
      # redis port number 
      port:  6379 
      # host and port can also be configured with url: as follows 
      # uri : redis://localhost:6379/1?timeout=5s 
      # If redis has set a password, you need to add password 
      # password: 
      # Specify the global configuration of timeout in milliseconds 
      expireAfterWriteInMillis:  5000 
      # Cluster mode 
      # mode: MasterSlave # ( master-slave mode) 
      poolConfig: 
        minIdle: 5
        maxIdle: 20
        maxTotal: 50

3. Annotate to enable caching

Use activate on the startup @EnableCreateCacheAnnotationclass @CreateCache, use @EnableMethodCacheactivate @Cached, and @EnableMethodCacheyou also need to specify the path to scan the package.

4. Use of @CreateCach

Creating Cache instances through @CreateCacheannotations high flexibility.

Property sheet:

Create a Cache instance in a Spring bean using the @CreateCache annotation. E.g:

@CreateCache(expire = 100)
private Cache<Long, UserDO> userCache;

Attributes Defaults illustrate
area “default” If you need to connect multiple cache systems, you can configure multiple cache areas. This attribute specifies the name of the area to be used.
name undefined Specify the name of the cache, it is not required, if not specified, the class name + method name will be used. name will be used for the key prefix of the remote cache. Also in statistics, a short and meaningful name improves readability. If the sum of the two @CreateCacheis the namesame area, they will point to the same Cacheinstance
expire undefined The default timeout of the Cache instance is defined. If the annotation is not defined, the global configuration will be used. If the global configuration is not defined at this time, it will be infinite.
timeUnit TimeUnit.SECONDS Specify the unit of expire
cacheType CacheType.REMOTE The type of cache, including CacheType.REMOTE, CacheType.LOCAL, CacheType.BOTH. If it is defined as BOTH, it will use LOCAL and REMOTE to combine into a two-level cache
localLimit undefined If cacheType is CacheType.LOCAL or CacheType.BOTH, this parameter specifies the maximum number of elements in the local cache to control memory usage. When the annotation is not defined, the global configuration will be used. If the global configuration is not defined at this time, take 100
serialPolicy undefined If cacheType is CacheType.REMOTE or CacheType.BOTH, specifies the serialization method of the remote cache. The optional values ​​built into JetCache are SerialPolicy.JAVA and SerialPolicy.KRYO. When the annotation is not defined, the global configuration will be used. If the global configuration is not defined at this time, SerialPolicy.JAVA will be used.
keyConvertor undefined Specifies the conversion method of KEY, which is used to convert complex KEY types to types acceptable to the cache implementation. The built-in optional values ​​of JetCache are KeyConvertor.FASTJSON and KeyConvertor.NONE. NONE means no conversion, FASTJSON converts the complex object KEY into String through fastjson. If not defined on the annotation, the global configuration is used.

Enumeration: I define a jetCache cache in my TestServiceImplclass , and use @CreateCachethe annotation to indicate that the object is the object used for caching. The code is as follows:

// Define a jetCache cache, the name is jetCache_, the expiration time is 3600 seconds 
    // timeUnit defaults to TimeUnit.SECONDS, which can be replaced with other time units 
    // area uses the default configuration (can not be written), if you want to use other cache systems , the name must be specified 
    @CreateCache (area = "default" ,name = "jetCache_" ,expire = 3600 ,timeUnit = TimeUnit.SECONDS)
     private Cache<String,String> jetCache;

Then I wrote two methods in this implementation class, one to store the value in the cache and one to get the value from the cache, corresponding /put-cacheto /get-cachetwo interfaces respectively, the code is as follows

@CreateCache(area = "default",name = "jetCache_",expire = 3600,timeUnit = TimeUnit.SECONDS)
    private Cache<String,String> jetCache;

    @Override
    public void putCache() {
        String key = "mike";
        jetCache.put(key, "Just save something" );
    }

    @Override
    public void getCache() {
        String key = "mike";
        String value = jetCache.get(key);
        System.out.println("value = " + value);
    }

First call and /put-cachestore the data, then call /get-cachethe data, the console output is as follows:

It can be seen that the previously stored can keybe value, and the usage is similar to the map collection, which realizes the realization of caching through JetCache.

The more commonly used methods are putand getmethods . CacheFor details of the interface, APIplease refer to the [official documentation] , so I won’t go into details here.

5. The use of method caching

The JetCache method cache is similar to SpringCache. It natively provides TTL support to ensure eventual consistency and supports second-level caching.

In the spring environment, use the @Cached annotation to add a cache to a method, @CacheUpdateupdate the cache, and @CacheInvalidateremove cached elements. Annotations can be added to the interface or to the class. The annotated class must be a spring bean, such as the example in the official documentation :

public interface UserService {
    @Cached(, expire = 3600)
    User getUserById(long userId);

    @CacheUpdate()
    void updateUser(User user);

    @CacheInvalidate()
    void deleteUser(long userId);
}

5.1 Use of @Cached

Property sheet:

@CachedThe annotation is very similar to the @CreateCache attribute, but there are a few more:

Attributes Defaults illustrate
area “default” If multiple cache areas are configured in the configuration, specify which area to use here
name undefined Specify the unique name of the cache. It is not required. If not specified, the class name + method name will be used. name will be used for the key prefix of the remote cache. Also in statistics, a short and meaningful name improves readability.
key undefined Use SpEL to specify the key. If not specified, it will be automatically generated based on all parameters.
expire undefined overtime time. If the annotation is not defined, the global configuration will be used, and if the global configuration is not defined at this time, it will be infinite
timeUnit TimeUnit.SECONDS Specify the unit of expire
cacheType CacheType.REMOTE The type of cache, including CacheType.REMOTE, CacheType.LOCAL, CacheType.BOTH. If it is defined as BOTH, it will use LOCAL and REMOTE to combine into a two-level cache
localLimit undefined If cacheType is LOCAL or BOTH, this parameter specifies the maximum number of elements in the local cache to control memory usage. If the annotation is not defined, the global configuration will be used, and if the global configuration is not defined at this time, it will be 100
localExpire undefined Applicable only when cacheType is BOTH, specify a different timeout for the in-memory cache, usually less than expire
serialPolicy undefined Specifies the serialization method of the remote cache. Optional values ​​are SerialPolicy.JAVA and SerialPolicy.KRYO. If the annotation is not defined, the global configuration will be used. If the global configuration is not defined at this time, it will be SerialPolicy.JAVA
keyConvertor undefined Specifies the KEY conversion method, which is used to convert complex KEY types to types acceptable to the cache implementation. Currently, KeyConvertor.FASTJSON and KeyConvertor.NONE are supported. NONE means no conversion, FASTJSON can convert complex object KEY into String. If not defined on the annotation, the global configuration will be used.
enabled true Whether to activate caching. For example, add a cache annotation to a dao method. Since there is no cache in some calling scenarios, you can set enabled to false. Normal calls will not use the cache. You can use CacheContext.enableCache to activate the cache in the callback where needed. The activated flag is on ThreadLocal. After the flag is set, all caches with enable=false are activated
cacheNullValue false Whether to cache when the method returns null
condition undefined Use SpEL to specify conditions, and only query in the cache if the expression returns true
postCondition undefined Use SpEL to specify a condition, and update the cache only when the expression returns true, the evaluation is performed after the method is executed, so you can access #result

public interface TestService {

    @Cached(, expire = 3600,cacheType = CacheType.LOCAL)
    UserInfoResp queryUserInfo(IdReq req);

}

Secondly, there are two other things to pay attention to when using the method cache, which is to update and understand how the cache operates. JetCache is similar to Spring Cache, and it is also implemented through annotations, namely: @CacheUpdate@CacheInvalidate

5.2 Use of @CacheUpdate

Property sheet:

Attributes Defaults illustrate
area “default” If multiple cache areas are configured in the configuration, specify which area to use here, pointing to the corresponding @Cached definition.
name undefined Specifies a unique name for the cache, pointing to the corresponding @Cached definition.
key undefined Specify key using SpEL
value undefined Specify value using SpEL
condition undefined Use SpEL to specify a condition, if the expression returns true, the update is performed, and the method result can be accessed#result

Example:

public interface TestService {

    @Cached(, expire = 3600,cacheType = CacheType.LOCAL)
    UserInfoResp queryUserInfo(IdReq req);

    @CacheUpdate()
    void saveUserInfo(IdReq req);

}

5.3 Use of @CacheInvalidate

Property sheet:

Attributes Defaults illustrate
area “default” If multiple cache areas are configured in the configuration, specify which area to use here, pointing to the corresponding @Cached definition.
name undefined Specifies a unique name for the cache, pointing to the corresponding @Cached definition.
key undefined Specify key using SpEL
condition undefined Use SpEL to specify a condition, if the expression returns true, the update is performed, and the method result can be accessed#result

Example:

public interface TestService {

    @Cached(, expire = 3600,cacheType = CacheType.LOCAL)
    UserInfoResp queryUserInfo(IdReq req);

    @CacheUpdate()
    void saveUserInfo(IdReq req);

    @CacheInvalidate()
    void deleteUserInfo(IdReq req);
}

Note: When using @CacheUpdateand @CacheInvalidate, related cache operations may fail (such as network IO errors), so it is very important to specify the cache timeout.

5.4 Use of @CacheRefresh

Property sheet:

Attributes Defaults illustrate
refresh undefined refresh interval
timeUnit TimeUnit.SECONDS time unit
stopRefreshAfterLastAccess undefined Specify how long the key has not been accessed before it stops refreshing. If it is not specified, it will be refreshed all the time.
refreshLockTimeout 60 seconds When the cache of type BOTH/REMOTE is refreshed, only one server is refreshing at the same time, and this server will place a distributed lock in the remote cache. This configuration specifies the timeout period of the lock

Example: every 10 seconds, flush the cache

public interface TestService {

    @Cached(, expire = 3600,cacheType = CacheType.LOCAL)
    @CacheRefresh(refresh = 10)
    UserInfoResp queryUserInfo(IdReq req);

}

5.5 Use of @CachePenetrationProtect

The principle of cache penetration protection is to protect the concurrent loading behavior when the cache access is not hit. The current version implements protection within a single JVM, that is, only one thread loads the same key in the same JVM, and other threads wait for the result.

Property sheet:

Attributes Defaults illustrate
value true Whether to open
timeout undefined Protection time, the default integer maximum value, other threads wait for the timeout period, and execute the method after the timeout
timeUnit TimeUnit.SECONDS time unit

Example:

public interface TestService {

    @Cached(, expire = 3600,cacheType = CacheType.LOCAL)
    @CachePenetrationProtect
    UserInfoResp queryUserInfo(IdReq req);

}

Third, the experience of stepping on the pit

1. Startup error

I used <version>2.6.0</version>this at first, and then the version of the parent project of my project spring-boot-starter-parentis <version>2.1.4.RELEASE</version>that I configure the local cache scheme to start without error, but when I configure the remote cache scheme to start, an error is reported. This is due to jedis and spring-boot -Starter-data-redis’s maven-dependent version is incompatible, which is a common problem. So if this happens, just change the version of JetCache, it should be able to solve it.

<!-- JetCache--> 
        < dependency > 
            < groupId > com.alicp.jetcache </ groupId > 
            < artifactId > jetcache-starter-redis </ artifactId > 
            <!-- before replacement --> 
            <!--< version>2.6.0</version>--> 
            <!-- after replacement--> 
            < version > 2.4.4 </ version > 
        </ dependency >

2. The @CreateCache annotation is invalid

My code is as follows: define a Cachecache , two methods, one is to store data in the cache, the other is to fetch data from the cache, corresponding /put-cacheto /get-cachetwo interfaces, no matter which interface is called, report NullPointerException, yml configuration and startup annotation Yes, but the annotation does not take effect.

@CreateCache(area = "default",name = "jetCache_",expire = 3600,timeUnit = TimeUnit.SECONDS,cacheType = CacheType.LOCAL)
    private Cache<String,String> jetCache;

    @Override
    public void putCache() {
        String key = "mike";
        jetCache.put(key, "Just save something" );
    }

    @Override
    public void getCache() {
        String key = "mike";
        String value = jetCache.get(key);
        System.out.println("value = " + value);
    }

This thing is also caused by incompatible versions of dependencies, so I continue to check the [maven repository] and try to find JetCachea version. Finally found <version>2.5.9</version>this version. PS: Personally, I can only find it through this stupid method~~

        <dependency>
            <groupId>com.alicp.jetcache</groupId>
            <artifactId>jetcache-starter-redis</artifactId>
            <!--<version>2.6.0</version>-->
            <!--<version>2.4.4</version>-->
            <!--<version>2.6.5</version>-->
            <!--<version>2.5.3</version>-->
            <version>2.5.9</version>
        </dependency>

First call and /put-cachestore the data, then call /get-cachethe data, the console output is as follows:

You can see that the @CreateCacheannotation has taken effect.

3. The @Cached annotation is invalid

Reference blog: Introduction to Alibaba
[‘s open source caching framework JetCache] JetCache
and configuration instructions



Leave a Comment

Your email address will not be published. Required fields are marked *