Home  >  Article  >  Java  >  How to implement Redis multi-level cache based on Java

How to implement Redis multi-level cache based on Java

WBOY
WBOYforward
2023-05-13 19:52:171027browse

1. Multi-level caching

1. Traditional caching solution

After the request reaches tomcat, it first goes to redis to get the cache. If there is no hit, it goes to mysql to get it

How to implement Redis multi-level cache based on Java

2. Multi-level caching solution

  • # The number of concurrent requests of tomcat is much smaller than that of redis, so tomcat will become a bottleneck

  • Use each link of request processing to add cache respectively to reduce the pressure on tomcat and improve service performance

How to implement Redis multi-level cache based on Java

# #2. JVM local cache

The cache is stored in the memory, and the data reading speed is faster, which can greatly reduce the access to the database and reduce the pressure on the database

Distributed cache, Such as redis

- Advantages: Large storage capacity, good reliability, can be shared in the cluster
- Disadvantages: There is network overhead for accessing the cache
- Scenario: Large amount of cached data, high reliability, needs to be in the cluster Shared data in

Process local cache, such as HashMap, GuavaCache

- Advantages: Reading local memory, no network overhead, faster
- Disadvantages: Storage capacity Limited, low reliability (such as lost after restarting), cannot be shared in the cluster
- Scenario: high performance requirements, small amount of cached data

1. Practical case

  • Caffeine is a high-performance local cache library developed based on java8 that provides nearly the best hit rate.

  • This is currently used for the internal cache of spring

  • <dependency>
         <groupId>com.github.ben-manes.caffeine</groupId>
         <artifactId>caffeine</artifactId>
         <version>3.0.5</version>
     </dependency>
    package com.erick.cache;
    
    import com.github.benmanes.caffeine.cache.Cache;
    import com.github.benmanes.caffeine.cache.Caffeine;
    
    import java.time.Duration;
    
    public final class CacheUtil {
        private static int expireSeconds = 2;
        public static Cache<String, String> cacheWithExpireSeconds;
    
        private static int maxPairs = 1;
        public static Cache<String, String> cacheWithMaxPairs;
    
        static {
            /*过期策略,写完60s后过期*/
            cacheWithExpireSeconds = Caffeine.newBuilder()
                    .expireAfterWrite(Duration.ofSeconds(expireSeconds))
                    .build();
    
            /*过期策略,达到最大值后删除
             * 1. 并不会立即删除,等一会儿才会删除
             * 2. 会将之前存储的数据删除掉*/
            cacheWithMaxPairs = Caffeine.newBuilder()
                    .maximumSize(maxPairs)
                    .build();
        }
    
        /*从缓存中获取数据
         * 1. 如果缓存中有,则直接从缓存中返回
         * 2. 如果缓存中没有,则去数据查询并返回结果*/
        public static String getKeyWithExpire(String key) {
            return cacheWithExpireSeconds.get(key, value -> {
                return getResultFromDB();
            });
        }
    
        public static String getKeyWithMaxPair(String key) {
            return cacheWithMaxPairs.get(key, value -> {
                return getResultFromDB();
            });
        }
    
        private static String getResultFromDB() {
            System.out.println("数据库查询");
            return "db result";
        }
    }
    package com.erick.cache;
    
    import java.util.concurrent.TimeUnit;
    
    public class Test {
    
        @org.junit.Test
        public void test01() throws InterruptedException {
            CacheUtil.cacheWithExpireSeconds.put("name", "erick");
            System.out.println(CacheUtil.getKeyWithExpire("name"));
            TimeUnit.SECONDS.sleep(3);
            System.out.println(CacheUtil.getKeyWithExpire("name"));
        }
    
        @org.junit.Test
        public void test02() throws InterruptedException {
            CacheUtil.cacheWithMaxPairs.put("name", "erick");
            CacheUtil.cacheWithMaxPairs.put("age", "12");
    
            System.out.println(CacheUtil.getKeyWithMaxPair("name"));
            System.out.println(CacheUtil.getKeyWithMaxPair("age"));
    
            TimeUnit.SECONDS.sleep(2);
    
            System.out.println(CacheUtil.getKeyWithMaxPair("name")); // 查询不到了
            System.out.println(CacheUtil.getKeyWithMaxPair("age"));
        }
    }
3. Cache consistency

1. Common solutions

1.1 Set the validity period
  • to the cache Set the validity period and automatically delete it after expiration. It can be updated when querying again

  • Advantages: simple and convenient

  • Disadvantages: poor timeliness, the cache may be inconsistent before it expires

  • Scenario: Business with low update frequency and low timeliness requirements

1.2 Synchronous double writing
  • When modifying the database At the same time, directly modify the cache

  • Advantages: code intrusion, strong consistency between cache and database

  • Disadvantages: code intrusion, high coupling

  • Scenario: Cache data with high consistency and invalidity requirements

1.3 Asynchronous notification
  • Send an event notification when the database is modified, and the relevant services modify the cached data after listening to it

  • Advantages: low coupling, multiple cache services can be notified at the same time

  • Disadvantages: Timeliness is limited, there may be cache inconsistency issues

  • Scenario: Timeliness is average, there are multiple services that need to be synchronized

How to implement Redis multi-level cache based on Java

How to implement Redis multi-level cache based on Java

2. Canal-based asynchronous notification

  • is an open source project under Alibaba, based on java Development

  • Based on database incremental log analysis, providing incremental data subscription and consumption

  • The idea of ​​master-slave backup based on mysql

2.1 mysql master-slave replication

How to implement Redis multi-level cache based on Java

2.2 canal working principle
  • canal simulates MySQL slave Interactive protocol, pretending to be a MySQL slave, sending dump protocol to MySQL master

  • MySQL master receives the dump request and starts pushing the binary log to the slave (i.e. canal)

  • canal parses the binary log object (originally a byte stream)

The above is the detailed content of How to implement Redis multi-level cache based on Java. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete