一、缓存穿透
场景描述:
用户访问了一个数据库和缓存中都不存在的数据,此时不但会直接访问到数据库上,并且还无法查询到数据,因此没办法写缓存,这就造成下一次访问依然会重复上面的情况。此时缓存无法奏效,缓存就像被“穿透”了,每次都会直接访问数据库,一旦流量大时数据库很可能因无法承受压力而宕机。
解决方案:
1. 接口校验
一般情况下,用户访问的都是我们提供的页面,应该不存在大量访问不存在的key的情况,所以出现这种情况很可能是遭受了非法的网络攻击,我们应该在接受请求的时候增加用户鉴权、数据合法性校验等手段。
2. 缓存空值
当缓存和数据库都查不到值时,可以将空值写进缓存,但是设置一个较短的过期时间,根据实际情况调整。
3. 布隆过滤器
将所有可能存在的key存入布隆过滤器,布隆过滤器可以查询出其内部一定不存在的某个值,这样可以把不存在的key直接过滤掉,只有可能存在的key才会访问缓存和数据库。
布隆过滤器相比HashMap占用空间更小,因此布隆过滤器通常是最佳选择。
二、缓存击穿
场景描述:
假如有某个热点key,在缓存过期的一瞬间,同时有大量的访问请求涌入,由于缓存过期,请求最终会直接打进数据库,瞬时的巨大的访问量可能造成数据库因压力过大而崩溃。
解决方案:
1. 加互斥锁
在并发的多个请求中,只有第一个请求能拿到锁并执行数据库查询操作,其他拿不到锁的线程就阻塞等着,等到第一个线程将数据写入缓存,后续请求就可以直接走缓存了。
- 分布式锁(redis)
- 进程锁(文件锁)
注意:无论使用哪种锁,加锁时要按key维度去加锁,以实现多进程锁,否则不同的key之间还相互阻塞,会造成性能严重下降。
2. 热点数据不过期
直接将热点数据设置为永不过期,然后由异步任务去刷新缓存,这种方式只适用于流量特别巨大的场景。由于要隔一段时间才能刷新缓存,因此还要业务上还要考虑是否能接受一定时间内的数据不一致。
三、缓存雪崩
场景描述:
大量热点key设置了相同的过期时间,导致缓存在同一时间失效,瞬时的巨大访问量直接请求到数据库上,数据库因压力大增造成雪崩甚至宕机。
其实一眼看就知道这就是升级版的”缓存击穿“罢了,在上述解决方案的基础上,我们的解决方案也差不多。
- 加互斥锁:同上。
- 热点数据不过期:同上。
- 过期时间打散:可以在缓存的过期时间上加一个随机时间,使得他们的过期时间分布开来,不至于同一时间失效。
网友评论