分类
笔记 编程

缓存穿透 vs 缓存雪崩 vs 缓存失效

缓存穿透

场景描述

 一般的缓存系统,都是按照 key 去缓存查询,如果不存在对应的 value,就应该去后端系统查找(比如 DB)。如果 key 对应的 value 是一定不存在的,并且对该 key 并发请求量很大,就会对后端系统造成很大的压力,我们称之为缓存穿透

解决方案
  • 对查询结果为空的情况也进行缓存,缓存过期时间设置短一点(避免消耗太多的缓存空间),或者该 key 对应的数据 insert 了之后清理缓存
  • 对一定不存在的 key 进行过滤。可以把所有的可能存在的 key 放到一个大的 Bitmap 中,查询时通过该 Bitmap 过滤
  • 排查是否是自身程序或者数据的问题,亦或是外部恶意攻击或者爬虫,导致大量访问不存在的 key 值
分类
Java 编程

Spring Data 使用 Redis 自增方法报错

Spring Data Redis 的 RedisTemplate 对 Redis 进行了封装。在对某值调用increment()方法时报错:

redis ERR value is not an integer or out of range

redisTemplate.opsForValue().increment(key);

大家都知道redis序列化是将key,value值先转换为流的形式,再存储到redis中。

RedisTemplate是使用的JdkSerializationRedisSerializer序列化,序列化后的值包含了对象信息,版本号,类信息等,是一串字符串,所以无法进行数值自增操作。

而StringRedisTemplate序列化策略是字符串的值直接转为字节数组,所以存储到redis中是数值,所以可以进行自增操作。

分类
Java 笔记

Spring Boot集成Cache和Redis

构建基于Spring Boot 2.X应用,使用Cache,需要引入:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-cache</artifactId>
</dependency>

以前开发Spring用EhCache来做缓存。在做集群或分布式时,还是Redis比较好用。引入Spring Data Redis如下:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

注意这里会有jedis依赖。

在applicatin.yml配置Redis和Cache:

spring:
  cache:
    redis:
      cache-names:
      cache-null-values: false
      key-prefix: spring:cache
      time-to-live: 0
      use-key-prefix: true
    type: # Cache type. By default, auto-detected according to the environment.
  redis:
    database: 5
    url: # Connection URL. Overrides host, port, and password. User is ignored. Example: redis://user:password@example.com:6379
    host: 127.0.0.1
    port: 6379
    password:
    timeout: 3000
    jedis:
      pool:
        max-active: 200
        max-idle: 10
        max-wait: -1
        min-idle: 0

更多配置属性可参考Spring Boot官方说明:

新建RedisConfig类,增加如下方法:

/**
 * 定义缓存数据 key 生成策略的bean
 * 包名+类名+方法名+所有参数
 * @return
 */
@Bean
public KeyGenerator wiselyKeyGenerator(){
	return new KeyGenerator() {
		@Override
		public Object generate(Object target, Method method, Object... params) {
			StringBuilder buff = new StringBuilder();
			buff.append(target.getClass().getName());
			buff.append(method.getName());
			for (Object obj : params) {
				buff.append(obj.toString());
			}
			return buff.toString();
		}
	};
}