redis三大问题
缓存穿透(查不存在的数据,穿过了缓存)
一般业务系统的设计为查询缓存没有数据则查数据库。当查询请求查询的是缓存和数据库都没有的数据时,这一类查询就会一直透过缓存直接查数据库。当业务系统有大量这种查询请求时,必定会对数据库造成很大的访问压力。这种就称为缓存击穿
可能造成缓存穿透的原因
1、恶意攻击
2、代码错误
解决方法:
1、缓存空对象: 当查询的时候,如果缓存和数据库中都没有,我们就将这个数据以空的形式存放在缓存中,(或者是给一个false的标示)这样就不用去数据库就可以知道不存在,减少对数据库查询的次数,当我们这个值发生改变的时候,我们在重新进行赋值;
缓存空对象存在的问题:
1)需要占用缓存空间,若造成缓存击穿的原因是恶意攻击,则很有可能会将问题转移到缓存。针对这种问题可以将这类缓存空值的key设置一个很短的过期时间
2)增加了缓存会使缓存数据和存储数据不一致,数据同步会有一定的延迟。可以增加消息队列或者增加逻辑代码来及时更新缓存数据
2、使用布隆过滤器 BloomFilter
业务系统查询数据时,先从布隆过滤器判断该key是否存在,不存在则说明数据库也不存在,直接返回空。若存在则走正常流程。
这种方法适用于数据命中不高,数据相对固定实时性低(通常是数据集较大)的应用场景,代码维护较为复杂,但是缓存空间占用少
对于恶意攻击,往往key只会使用一次,即使缓存了也没有用,浪费缓存空间,这种场景适合使用布隆过滤器
两种方案的选择
- 对于空数据的key各不相同、key重复请求概率低的场景而言,应该选择第二种方案。
- 而对于空数据的key数量有限、key重复请求概率较高的场景而言,应该选择第一种方案。
缓存雪崩(大面积key失效)
1、大量key同一时间过期造成雪崩
2、缓存服务器宕机造成雪崩
解决方法:
1、对缓存做集群高可用部署,防止单节点宕机造成雪崩
2、对key过期时间增加一个随机数,防止同时大面积key过期,或者对热点数据设置为永不过期
3、使用Hystrix在应用层做熔断、限流、降级
缓存击穿(热点数据集中失效)
是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。
解决方法:
1、增加互斥锁
在走数据库查询的位置增加互斥锁
伪代码:
get{
data = getCache();
if(null == data){
lock{
// 此处一定要先再次查询缓存
data = getCache();
if(null == data){
data = getDB();
}
}
}
return data
}
2、热点数据设置永不过期
对热门访问key早早的做好了准备,让缓存永不过期;
两种方案对比:
- 互斥锁 (mutex key):这种方案思路比较简单,但是存在一定的隐患,如果构建缓存过程出现问题或者时间较长,可能会存在死锁和线程池阻塞的风险,但是这种方法能够较好的降低后端存储负载并在一致性上做的比较好。
- 永远不过期:这种方案由于没有设置真正的过期时间,实际上已经不存在热点 key 产生的一系列危害,但是会存在数据不一致的情况,同时代码复杂度会增大。