一、缓存的好与坏
1、缓存带来的回报
1)高速读写
缓存加速读写速度:CPU L1/L2/L3 Cache、Linux page Cache加速硬盘读写、浏览器缓存、Ehcache缓存数据库结果
2)降低后端负载
后端服务器通过前端缓存降低负载: 业务端使用Redis降低后端MySQL负载等
2、缓存带来的代价
1)数据不一致
缓存层和数据层有时间窗口不一致,和更新策略有关
2)代码维护成本
原本只需要读写MySQL就能实现功能,但加入了缓存之后就要去维护缓存的数据,增加了代码复杂度。
3)堆内缓存可能带来内存溢出的风险影响用户进程,如ehCache、loadingCache
堆、java虚拟机栈、方法区、本地方法栈、程序计数器
堆内缓存和远程服务器缓存redis的选择
1、堆内缓存一般性能更好,远程缓存需要套接字传输
2、用户级别缓存尽量采用远程缓存
3、大数据量尽量采用远程缓存,服务节点化原则
如何快速整合cache地址:https://blog.csdn.net/weixin_42083036/article/details/103388222
二、boot cache存在问题
1、生成key过于简单 容易冲突?
解决方案: 自定义 key generator
解决代码:
@Bean
public KeyGenerator simpleKeyGenerator() {
return (o, method, objects) -> {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(o.getClass().getSimpleName());
stringBuilder.append(".");
stringBuilder.append(method.getName());
stringBuilder.append("[");
for (Object obj : objects) {
stringBuilder.append(obj.toString());
}
stringBuilder.append("]");
return stringBuilder.toString();
};
}
2、无法设置过期时间 默认过期时间为永久?
解决方案:自定义 cacheManager 设置过期时间
解决代码:
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
return new RedisCacheManager(
RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),
this.getRedisCacheConfigurationWithTtl(600), // 默认策略,未配置的 key 会使用这个
this.getRedisCacheConfigurationMap() // 指定 key 策略
);
}
3、需要配置序列化方式 默认 jdk Serializable?
解决方案: 自定义序列化方式
解决代码:
private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(
RedisSerializationContext
.SerializationPair
.fromSerializer(jackson2JsonRedisSerializer)
).entryTtl(Duration.ofSeconds(seconds));
return redisCacheConfiguration;
}