一、缓存穿透
是用户访问的数据既不在缓存当中,也不在数据库中。
如果从数据库查询不到数据,则不写入缓存。这就导致每次请求都会到数据库进行查询,缓存也失去了意义。
当高并发或有人利用不存在的Key频繁攻击时,数据库的压力骤增,甚至崩溃,这就是缓存穿透问题。
场景
-
原来数据是存在的,但由于某些原因(误删除、主动清理等)在缓存和数据库层面被删除了,但前端或前置的应用程序依旧保有这些数据;
-
恶意攻击行为,利用不存在的Key或者恶意尝试导致产生大量不存在的业务数据请求。
解决方案
方案一:缓存空值(null)或默认值
方案二:业务逻辑前置校验
方案三:使用布隆过滤器请求白名单
方案四:用户黑名单限制
二、缓存雪崩
缓存中大量热点缓存采用了相同的实效时间,就会导致缓存在某一个时刻同时实效,请求全部转发到数据库
场景
-
大量热点key同时过期;
-
缓存服务故障;
解决方案
-
通常的解决方案是将key的过期时间后面加上一个
随机数
(比如随机1-5分钟),让key均匀的失效。 -
考虑用队列或者锁的方式,保证缓存单线程写,但这种方案可能会影响并发量。
-
热点数据可以考虑不失效,后台异步更新缓存,适用于不严格要求缓存一致性的场景。
-
双key策略,主key设置过期时间,备key不设置过期时间,当主key失效时,直接返回备key值。
-
构建缓存高可用集群(针对缓存服务故障情况)。
-
当缓存雪崩发生时,服务熔断、限流、降级等措施保障。
缓存击穿
单个热点key,在不停的扛着大并发,在这个key失效的瞬间,持续的大并发请求就会击破缓存,直接请求到数据库
解决方案
使用互斥锁(Mutex Key),只让一个线程构建缓存,其他线程等待构建缓存执行完毕,重新从缓存中获取数据。单机通过synchronized或lock来处理,分布式环境采用分布式锁。
热点数据不设置过期时间,后台异步更新缓存,适用于不严格要求缓存一致性的场景。
”提前“使用互斥锁(Mutex Key):在value内部设置一个比缓存(Redis)过期时间短的过期时间标识,当异步线程发现该值快过期时,马上延长内置的这个时间,并重新从数据库加载数据,设置到缓存中去。