问题缓存雪崩:
缓存服务器挂掉,或者热点缓存失效,导致大量的请求访问DB数据库,导致数据库连接不够用或数据库处理不过来,从而导致系统不可用。
类比缓存击穿:
缓存雪崩产生的原因--缓存曾经存在,只是失效或者缓存服务器挂掉
而缓存击穿,是指访问缓存中必然不存在的数据,故意绕过缓存,直接访问数据库导致的
简单描述一下缓存击穿的解决方案:当访问数据库中不存在的数据时,可以给这个key设置一个固定值,并设置过期时间,这样的话,大量的访问该key的请求,都被缓存挡住了;当key存在数据时,缓存也已经失效,在去访问,就可以访问数据库更新这个key的值了
解决方案:
1.限流: 加锁,控制进入数据库请求数量
private Lock lock = new ReentrantLock();
public String queryInfo(String key){
//step1:先从缓存中获取,获取不到,接着向下走
try{
//step2:加锁
lock.lock();
// step3:获取到锁后,再次从缓存中取数据
// 这样做的目的是,验证是否已经有其他请求已经查询到数据,并放入缓存中去了
// step4:到数据库中查询
// step5 : 查询的结果放入缓存
}finally{
// step6: 解锁
lock.unlock();
}
}
这种方案的缺点:
1) 线程阻塞,导致用户体验不好
2) 加锁的粒度太大,对所有进入到这个方法的请求加锁,即所有的查询都被一把锁锁住
2.服务降级 :把锁的粒度变小,使用 ConcurrentHashMap加锁
private Map<String,String> lockMap = new ConcurrentHashMap<>(); public String queryInfo(String key){ //step1:先从缓存中获取,获取不到,接着向下走 boolean lock = false; try{ // step4:到数据库中查询 // step5 : 查询的结果放入缓存 ,包括备份缓存 } |
优点:线程不阻塞,用户体验好
缺点:数据不一致,缓存维护复杂
3.写定时任务去刷新更新热点缓存