【Redis】Redis整合SSM&&Redis注解式缓存&&Redis中的缓存穿透、雪崩、击穿的原因以及解决方案(详解)

【Redis】Redis整合SSM&&Redis注解式缓存&&Redis中的缓存穿透、雪崩、击穿的原因以及解决方案(详解)_第1张图片

目录:

目录

一,SSM整合redis

二,redis注解式缓存

三,Redis中的缓存穿透、雪崩、击穿的原因以及解决方案(附图)


一,SSM整合redis

1.原因:

 整合SSM和Redis可以提升系统的性能、可伸缩性和可靠性,在分布式环境下更好地支持会话管理、消息队列和分布式锁等功能。

2.步骤:可以参考SSM整合mysql

导入pom依赖在Maven中添加Redis的依赖

2.9.0
1.7.1.RELEASE


	redis.clients
	jedis
	${redis.version}


	org.springframework.data
	spring-data-redis
	${redis.spring.version}

2.2.spring-redis.xml的相关配置

redis.properties

redis.hostName=127.0.0.1
redis.port=6379
redis.password=123456
redis.timeout=10000
redis.maxIdle=300
redis.maxTotal=1000
redis.maxWaitMillis=1000
redis.minEvictableIdleTimeMillis=300000
redis.numTestsPerEvictionRun=1024
redis.timeBetweenEvictionRunsMillis=30000
redis.testOnBorrow=true
redis.testWhileIdle=true
redis.expiration=3600

spring-redis.xml




    
    

    
    
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    

    
    
        
        
        
        
        
        
        
        
        
    

    
    
        
        
        
            
        
        
            
        
        
            
        
        
            
        
        
        
    

    
    
        
        
        
        
        
        
        
            
                
            
        
    

    
    

    
    

2.3.修改applicationContext.xml

如果spring配置文件中需要配置两个及以上的properties文件则需要在applicationContext.xml中进行配置处理,否则会出现覆盖的情况。



    
    
        
        
        
            
                classpath:jdbc.properties
                classpath:redis.properties
            
        
    
 

    
    
    

2.4.配置redis的key生成策略

CacheKeyGenerator.java

package com.zking.ssm.redis;
 
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.util.ClassUtils;
 
import java.lang.reflect.Array;
import java.lang.reflect.Method;
 
@Slf4j
public class CacheKeyGenerator implements KeyGenerator {
    // custom cache key
    public static final int NO_PARAM_KEY = 0;
    public static final int NULL_PARAM_KEY = 53;
 
    @Override
    public Object generate(Object target, Method method, Object... params) {
        StringBuilder key = new StringBuilder();
        key.append(target.getClass().getSimpleName()).append(".").append(method.getName()).append(":");
        if (params.length == 0) {
            key.append(NO_PARAM_KEY);
        } else {
            int count = 0;
            for (Object param : params) {
                if (0 != count) {//参数之间用,进行分隔
                    key.append(',');
                }
                if (param == null) {
                    key.append(NULL_PARAM_KEY);
                } else if (ClassUtils.isPrimitiveArray(param.getClass())) {
                    int length = Array.getLength(param);
                    for (int i = 0; i < length; i++) {
                        key.append(Array.get(param, i));
                        key.append(',');
                    }
                } else if (ClassUtils.isPrimitiveOrWrapper(param.getClass()) || param instanceof String) {
                    key.append(param);
                } else {//Java一定要重写hashCode和eqauls
                    key.append(param.hashCode());
                }
                count++;
            }
        }
 
        String finalKey = key.toString();
//        IEDA要安装lombok插件
        log.debug("using cache key={}", finalKey);
        return finalKey;
    }
}

二,redis注解式缓存

关于什么是Redis注解式:

注解式缓存是一种通过在方法上添加特定的注解来实现自动缓存的机制。在Java开发中,我们可以使用Spring框架提供的@Cacheable@CachePut@CacheEvict等注解来实现对Redis的缓存操作。

  1. @Cacheable注解:

    • 作用:标记方法的返回值可以被缓存,并且在下次调用该方法时,会直接从缓存中获取结果,而不会执行方法体内的逻辑。使用该注解会将查询结果放入Redis中下一次同样的查询就不会走数据库,而是走Redis.
    • 示例代码:
    @Cacheable(value = "myCache", key = "#id")
    public User getUserById(String id) {
        // 从数据库或其他数据源获取用户信息的逻辑
        return user;
    }
    

    【Redis】Redis整合SSM&&Redis注解式缓存&&Redis中的缓存穿透、雪崩、击穿的原因以及解决方案(详解)_第2张图片

    解释:以上代码表示将方法的返回值以键值对的形式缓存在,减少了数据访问对MySQL数据库的压力
  2. @CachePut注解:

    • 作用:标记方法的返回值需要更新缓存,即每次调用方法都会执行方法体内的逻辑,并将返回值存入缓存。
    • 示例代码:
      @CachePut(value = "myCache", key = "#user.id")
      public User updateUser(User user) {
          // 更新用户信息的逻辑
          return user;
      }
      
    解释:以上代码表示每次调用该方法都会执行方法体内的逻辑,该注解会将查询结果放入Redis中,类似于更新操作,即每次不管缓存中有没有结果,都从数据库查找结果,并将结果更新到缓存,并返回结果
  3. @CacheEvict注解:

    • 作用:标记方法会清除缓存中的指定数据。
    • 示例代码:
    @CacheEvict(value = "myCache", key = "#id")
    public void deleteUser(String id) {
        // 删除用户信息的逻辑
    }
    

    解释:以上代码表示调用该方法时会从名为"myCache"的缓存中移除key为参数"id"对应的缓存数据。

  4. CachePut和Cacheable的区别:
    Cacheable和CachePut都是Spring框架中用于缓存的注解,它们的主要区别是:

    Cacheable用于获取缓存中的数据,如果缓存不存在,就会执行方法并将返回值放入缓存中;而CachePut用于更新缓存中的数据,它每次都会执行方法,并将返回值放入缓存中。

    Cacheable和CachePut的key生成方式不同,Cacheable默认使用方法的参数作为key,可以通过key属性指定key的生成方式或使用SpEL表达式自定义key的生成方式;而CachePut默认使用Cacheable的默认key生成方式,也可以通过key属性指定key的生成方式。

    Cacheable和CachePut的Sync属性也不同,Cacheable默认为false,即异步处理;而CachePut默认为true,即同步处理。
     

通过使用这些注解,我们可以更加方便地实现对Redis的缓存操作,减少了手动管理缓存的复杂性。但需要注意的是,使用注解式缓存时,需要确保被缓存的方法的输入参数和返回值类型是可序列化的,以便在Redis中进行存储和读取。

此外,还可以通过配置Spring框架的缓存管理器、缓存策略等来进一步优化和配置缓存行为。具体的配置和使用细节可以参考Spring框架的文档和教程。

三,Redis中的缓存穿透、雪崩、击穿的原因以及解决方案(附图)

  1. 缓存穿透(Cache Penetration):

    • 原因当请求查询一个不存在于缓存和数据库中的数据时,每次查询都会直接访问数据库,导致对数据库的频繁访问,增加数据库负载。情景:客户端发送大量的不可响应的请求:比如发送一个id为-999的用户
    • 解决方案:
      • 布隆过滤器(Bloom Filter):用于判断请求的数据是否存在于缓存或数据库中。使用布隆过滤器可以快速过滤掉一部分不存在的数据,避免对数据库的无效查询。
      • 空值缓存(Null Object Caching):将不存在的数据也缓存起来,但设置一个较短的过期时间,以便下次查询时可以从缓存中获取。

        注意事项:

        使用空值作为缓存的时候,key设置的过期时间不能太长,防止占用太多redis资源
        对空值缓存是一种被动的防御方式,当遇到黑客暴力请求很多不存在的数据就需要写入大量的null值到Redis中,可能导致Redis内存占用不足的情况
        使用布隆过滤器,可以在用户访问的时候判断该资源是否存在,不存在则直接拒绝访问
        布隆过滤器是有一定的误差,所以一般需要配合一些接口流量的限制(规定用户在一段时间内访问的频率)、权限校验、黑名单等来解决缓存穿透的问题
        【Redis】Redis整合SSM&&Redis注解式缓存&&Redis中的缓存穿透、雪崩、击穿的原因以及解决方案(详解)_第3张图片

  2. 缓存雪崩(Cache Avalanche):

    • 原因当缓存中的大量数据同时过期或失效时,所有请求都会直接访问数据库,导致数据库压力骤增,甚至导致数据库宕机。
    • 解决方案:
      • 随机过期时间(Randomized Expiration):为缓存中的数据设置随机的过期时间,以避免大量数据同时过期。
      • 并发控制(Concurrency Control):使用分布式锁或互斥机制,确保只有一个线程可以重新加载缓存数据,避免重复查询。
  3. 缓存击穿(Cache Miss):

    • 原因当某个热点数据过期或失效时,大量请求同时涌入,导致并发查询数据库,增加数据库压力。
    • 解决方案:
      • 互斥锁(Mutex Lock):在缓存失效的情况下,使用互斥锁来确保只有一个请求可以查询数据库,并将查询结果进行缓存,其他请求等待缓存更新后再获取数据。
      • 提前加载(Preloading):提前加载热点数据到缓存中,并设置较长的过期时间,以避免热点数据过期后被击穿。

你可能感兴趣的:(缓存,redis,java)