缓存雪崩
缓存雪崩表示在某一时间段,缓存集中失效,导致请求全部请求到数据库对数据库造成巨大压力。
解决方案
1、缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
2、如果缓存数据库是分布式部署,将热点数据均匀分布在不同的缓存数据库中。
3、设置热点数据永远不过期。
缓存穿透
缓存穿透是指大量请求数据库和缓存中都不存在的数据,对数据库造成巨大压力。
解决方案
1、布隆过滤器,可以先判断key值是否存在,如果不存在,则不访问redis,那这样就可以拦截大量的请求,布隆过滤器恰好可以实现这样的需求。
2、缓存空对象
当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源;
但是这种方法会存在两个问题:
如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;
即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。
缓存击穿
缓存击穿跟缓存雪崩类似,区别就是缓存雪崩是群体失效,缓存击穿是单体失效,比如一个非常热点的数据。缓存击穿是指热点key在某个时间点过期的时候,而恰好在这个时间点对这个Key有大量的并发请求过来,从而大量的请求直接请求到数据库。
解决方案
1.使用互斥锁(mutex lock):
在缓存失效的时候,不是直接请求DB,而是先加分布式锁(比如redis的setNx),如果加锁成功,再进行load db的操作并回设缓存;如果加锁失败,说明已经有别的进程在加锁重设缓存,我们只需要等待重试或者直接返回客户端失败让用户手动重试。
2、提前更新缓存:
当我们读取缓存的时候,先判断它是否快到过期时间,如果是则在返回缓存数据的同时,后台异步请求DB重设缓存,更新它的过期时间。而如果我们获取缓存是缓存已经过期,则还需要我们按照上一个方案处理。
3、设置热点数据永远不过期