缓存击穿
/**
* 缓存击穿:高并发时,当一个key非常热点(热销品),在不停的扛着大并发,当这个key在失效的瞬间,持续的大并发就击穿缓存,直接请求数据库后再缓存数据,导致性能下降
* 解决方案:永不过期 或 加锁排队 或 两者都有
*
* @param key 键
* @return {@link String}
*/
public String cacheBreakdown(String key) {
String value = stringRedisTemplate.opsForValue().get(key);
if (StringUtils.isNotBlank(value)) {
return value;
}
synchronized (this) {
value = stringRedisTemplate.opsForValue().get(key);
if (StringUtils.isNotBlank(value)) {
return value;
}
// 从数据库中获取数据
value = selectDb(key);
stringRedisTemplate.opsForValue().set(key, value, Duration.ofHours(1L));
}
return value;
}
缓存雪崩
/**
* 缓存雪崩:缓存集中过期,或者缓存服务器宕机,导致大量请求访问数据库,造成数据库瞬间压力过大,宕机
* 解决方案:加锁排队 和 随机失效时间 和 redis集群部署
*
* @param key 钥匙
* @return {@link String}
*/
public String cacheAvalanche(String key) {
String value = stringRedisTemplate.opsForValue().get(key);
if (StringUtils.isNotBlank(value)) {
return value;
}
synchronized (this) {
value = stringRedisTemplate.opsForValue().get(key);
if (StringUtils.isNotBlank(value)) {
return value;
}
// 从数据库中获取数据
value = selectDb(key);
// 设置随机失效时间
long hour = ThreadLocalRandom.current().nextLong(1L, 31L);
stringRedisTemplate.opsForValue().set(key, value, Duration.ofHours(hour));
}
return value;
}
缓存穿透
/**
* 缓存穿透:数据库不存在且缓存中也不存在,导致每次请求都会查询数据库,这时的请求很可能是攻击者,伪造不存在的 key ,导致数据库压力过大或宕机
* 解决方案:参数校验(如ID≤0的key值请求一律返回空) 和 缓存空对象 和 使用 bloom 过滤器
*
* @param key 钥匙
* @return {@link String}
*/
public String cachePenetration(String key) {
// RedissonClient redissonClient = Redisson.create();
RBloomFilter<Long> bloomFilter = redissonClient.getBloomFilter("bloom:filter:data");
if (!bloomFilter.contains(Long.parseLong(key))) {
return null;
}
String value = stringRedisTemplate.opsForValue().get(key);
if (StringUtils.isNotBlank(value)) {
return value;
}
synchronized (this) {
value = stringRedisTemplate.opsForValue().get(key);
if (StringUtils.isNotBlank(value)) {
return value;
}
// 从数据库中获取数据
value = selectDb(key);
if (StringUtils.isBlank(value)) {
// 缓存空对象
stringRedisTemplate.opsForValue().set(key, "{}", Duration.ofMinutes(10L));
return value;
}
// 设置随机失效时间
long hour = ThreadLocalRandom.current().nextLong(1L, 31L);
stringRedisTemplate.opsForValue().set(key, value, Duration.ofHours(hour));
}
return value;
}