//TODO 产生堆外内存溢出异常,OutOfDirectMemory //1).springBoot2.0以后使用lettuce作为操作redis的客户端,它使用netty进行网络通信 //2).lettuce的bug导致netty堆外内存溢出,netty如果没有指定堆外内存,默认使用-Xmx //3).可以通过-Dio.netty.maxDirectMemory进行设置,不能使用-Dio.netty.maxDirectMemory只去调大堆外内存 //解决方案:
/** * 1).升级lettuce客户端, * 2).切换使用jedis * * lettuce,jedis来操作redis的底层客户端,spring在底层对lettuce和jedis进行了再封装redisTemplate * * @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) * public class RedisAutoConfiguration */(1.)自动配置了哪些? CacheAutoConfiguration会导入 RedisCacheConfiguration; 自动配置好缓存管理器redisCacheManager
(2.)配置使用redis作为缓存 在properties文件中配置
spring.cache.type=redis spring.cache.redis.time-to-live=36000003.)测试使用缓存 如下是基本注解的解释 springCache: https://docs.spring.io/spring/docs/5.1.17.RELEASE/spring-framework-reference/integration.html#cache
@Cacheable: Triggers cache population. 触发将数据保存到缓存的操作 @CacheEvict: Triggers cache eviction. 触发将数据从缓存中删除的操作 @CachePut: Updates the cache without interfering with the method execution. 不影响方法的执行 更新缓存 @Caching: Regroups multiple cache operations to be applied on a method. 组合以上操作 @CacheConfig: Shares some common cache-related settings at class-level. 在类级别共享缓存的相同配置1).开启注解功能 @EnableCaching 2).只需要使用注解就可以完成缓存操作 1.1 测试:@Cacheable
/** * 1.每一个缓存的数据 我们需要指定放入到哪个名字的缓存 * 2.@Cacheable({"category"}) //代表当前方法的结果需要进行缓存 如果缓存中有 该方法不调用,如果缓存中没有,会调用方法,最后将方法的结果放入缓存 * 3.默认行为 * 1)如果缓存中有,方法不进行调用。 * 2)key默认自动生成,缓存的名字:SimpleKey[] * 3)缓存的value的值,默认使用java序列化机制,将序列化后的数据保存到redis * 4)默认ttl时间:-1; 默认ttl时间永不过期 * / //指定缓存生成的key key属性:支持springEL表达式 注意字符串要加单引号 //sync = true -->加锁,解决缓存击穿,本地锁足够 @Cacheable(value = {"category"},key = "'level1Categorys'",sync = true) public List<CategoryEntity> getLevel1Category()1.2 测试:@Caching 组合以上操作
/** * 级联更新所有关联的数据 * @CacheEvict 缓存失效模式 触发将数据从缓存中删除的操作 * @param category */ // @CacheEvict(value = {"category"},key = "'getLevel1Categorys'")//单引号 //同时进行多种缓存操作 @Caching(evict = { @CacheEvict(value = {"category"},key = "'getLevel1Categorys'"), @CacheEvict(value = {"category"},key = "'getCatelogJson'") }) public void updateCascade(CategoryEntity category)将数据保存为json的格式 自定义RedisCacheConfiguration 即可 参考源码:
自定义缓存配置:
import org.springframework.boot.autoconfigure.cache.CacheProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; @EnableConfigurationProperties(CacheProperties.class) //开启配置文件支持 @Configuration @EnableCaching public class MyCacheConfig { // @Autowired // CacheProperties cacheProperties; /** * * @return */ @Bean RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){ RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); //key和value的序列化器 config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())); config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())); CacheProperties.Redis redisProperties = cacheProperties.getRedis(); //让配置文件中的配置生效 ttl等 if (redisProperties.getTimeToLive() != null) { config = config.entryTtl(redisProperties.getTimeToLive()); } if (redisProperties.getKeyPrefix() != null) { config = config.prefixKeysWith(redisProperties.getKeyPrefix()); } if (!redisProperties.isCacheNullValues()) { config = config.disableCachingNullValues(); } if (!redisProperties.isUseKeyPrefix()) { config = config.disableKeyPrefix(); } return config; } }1、读模式
缓存穿透,查询一个null值 。解决:缓存空数据,properties文件中:spring.cache.redis.cache-null-values=true即可缓存击穿,大量并发进来同时查询一个正好过期的数据 。 解决:加锁大量并发只让一个去查,其他人等待,查到以后释放锁,其他人获取到锁,先查缓存,就会有数据,不用去db查询缓存雪崩:缓存雪崩是指在我们设置缓存时key采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩 解决:原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。如在properties文件配置 spring.cache.redis.time-to-live=36000002、写模式
读写加锁引入Cannal,感知到MySQL的更新去更新数据库读多写多,直接去数据库查询总结: 常规数据,(读多写少,及时性,一致性要求不高的数据):完全可以使用spring-Cache解决:写模式 特殊数据:特殊设计
热爱生活 热爱技术 !!!
