解决缓存击穿问题
当我们将数据放在缓存中,每次查询先访问缓存,如果缓存中有数据,就直接返回数据,如果没有,就去数据库里面查询,查询之后将数据添加到缓存中。但是每次缓存中的数据都会设置过期时间,如果刚刚好数据过期的数据,高并发情况发生了,假如这是有1W的并发量同时访问,那么就会发生这些请求直接访问数据库,给数据库造成一定的压力,甚至数据库服务崩掉,这就是缓存击穿的问题
在高并发下,多线程同时查询同一个资源,如果缓存中没有这个资源,那么这些线程都会去数据库查找,对数据库造成极大压力,缓存失去存在的意义
缓存穿透:在高并发下,多线程同时查询同一个不存在的资源,这个资源数据库里不存在,缓存里肯定也是不存在的,如果这样的话,也是缓存击穿问题
下面我们来写一些伪代码,演示一下:
正常逻辑:
public Object getOrder(Long id){
//先查询redis
Order order = redisClient.get(id);
//redis命中
if(order != null){
return order;
}
try{
//查询数据库
Order order = orderService.getOrderById(id);
if(order != null){
//查询到的数据添加到redis
redisClient.set(id,order);
return order;
}
} catch (Exception e){
e.printStackTrace();
}
}
上述代码就有可能出现缓存击穿问题,接下来我们来预防一下,使用我之前写的文章中的redis分布式锁
修改后逻辑:
public Object getOrder(Long id){
//先查询redis缓存
Order order = redisClient.get(id);
//redis命中
if(order != null){
return order;
}
try{
//添加redis分布式锁
redisLock.lock(id);
//先查询redis缓存
Order order = redisClient.get(id);
//redis命中
if(order != null){
return order;
}
//查询数据库
Order order = orderService.getOrderById(id);
if(order != null){
//查询到的数据添加到redis
redisClient.set(id,order);
return order;
}
} catch (Exception e){
e.printStackTrace();
} finally {
redisLock.unlock(id);
}
}
上面的代码就是改造过的,添加了分布式锁。
当缓存中的数据失效之后,如果这是出现大量的并发情况,就可以使用redis分布式锁解决了。因为当缓存数据失效后,多线程并发过来时,第一个请求会获取锁,然后只有一个请求去查询数据库,查询结束后,将数据添加到缓存,这时候释放锁,其他请求获取锁之后,先查询缓存,这是缓存中已经有数据了,就避免了去查询数据库了。这时无论多少的并发量都没关系啦,因为这时就可以从缓存中查询数据了。。。
解决缓存击穿问题可以参考文章
缓存穿透、缓存雪崩、缓存击穿