缓存穿透
用户查询在数据库中没有的数据,当然在缓存中自然也不会有。每次用户查询,缓存中没有,再去数据库查一遍,最后返回空(相当于进行了两次无用的查询)。如果每次都拿一个不存在的值去查询数据库,可能会导致数据库压力增大。
解决办法
-
缓存空值
之所以发生穿透,是因为在缓存中没有存储这些key,从而每次都查询数据库。可以在缓存中设置这些key对应的值为null,后面查询这个key的时候就不用再去数据库查询。
但是这种方法会存在两个问题:- 如果空值被缓存起来,这就意味着需要更多的空间存储更多的键。
- 即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致的业务会有影响。
-
BloomFilter(布隆过滤器)
布隆过滤器类似于一个hbase set用来判断某个元素key是否存在于某个集合中。我们把有数据的key都放到布隆过滤器中,每次查询的时候都先去布隆过滤器判断,如果没有就直接返回null。
但是布隆过滤器没有删除操作,对于删除的key,查询就会经过布隆过滤器然后查询缓存再查询数据库。所以布隆过滤器可以结合缓存空值使用,对于删除的key,可以在缓存中缓存null。
缓存击穿
在高并发的情况下,大量的请求同时查询同一个key,此时这个key正好失效了,就会导致同一时间,这些请求都去查询数据库,这种现象称为缓存击穿。
解决办法
- 设置热点数据永不过期
从缓存层面来看,没有设置过期时间,所以不会出现热点key过期后产生的问题。但是会占用缓存空间。 - 加互斥锁
采用分布式锁,只有拿到锁的第一个线程去请求数据库,然后插入缓存,每次拿到锁的时候都去查询一下缓存有没有。
缓存雪崩
指的是某一格时间段缓存集中过期失效,原本应该访问缓存的请求都去查询数据库了,而对数据库CPU和内存造成巨大压力。或者出现缓存服务器宕机。
解决办法
- 解决热点数据集中失效问题
- 设置不同的失效时间
- 采用缓存击穿的解决办法,加锁
- 永不失效,就是采用定时任务对快要失效的缓存进行更新缓存和失效时间。
- 采用集群,降低服务器宕机的概率。