什么是缓存击穿:缓存击穿问题也被称为热点key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来压力。
常见的有两种解决方案
- 互斥锁
- 如果有无数个请求,并发执行,因为加了锁,只会有一个线程完成构建,其他的都是阻塞、等待、重试卡在这里,缺点是互相等待,
- 比如有1000个线程来了,其实只有一个线程在做构建,其他线程都在等待,如果构建时间比较久(500ms)在这段时间内所有线程都要等待,性能要差一点
- 逻辑过期
- 造成缓存击穿的原因就是ttl过期,那么就不设置ttl
代码实现:
- 造成缓存击穿的原因就是ttl过期,那么就不设置ttl
public <R,ID> R queryWithLogicalExpire(String keyPrefix,ID id,Class<R>type,Function<ID,R>dbFallback,Long time,TimeUnit unit){
String key = keyPrefix +id;
//从redis中按查询商品缓存
String json = stringRedisTemplate.opsForValue().get(key);
if(StrUtil.isBlank(json)){
return null;
}
//命中
RedisData redisData = JSONUtil.toBean(json,RedisData.class);
R r = JSONUtil.toBean((JSONObject)redisData.getData(),type);
LocalDateTime expireTime = redisData.getExpireTime();
if(expireTime.isAfter(LocalDateTime.now())){
//未过期,直接返回店铺信息
return r;
}
String lockKey = "LOCK" +id;
boolean isLock = tryLock(lockKey);
if(isLock){
CACHE_REBUILD_EXECUTOR.submit(()->{
try{
R r1 = dbFallback.apply(id);
//写入Redis
this.setWithLogicalExpire(key,r1,time,unit);
}catch(Exception e){
throw new RuntimeException(e);
}finally {
unlock(key);
}
});
}
return r;
}