1.缓存穿透、雪崩、击穿产生的原因
(1)缓存穿透
<1>查询一个不存在的数据
<2>从缓存redis没有命中,需要从mysql数据库查询,查不到数据则不写入缓存
<3>这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透
(2)缓存雪崩
<1>设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效
<2>请求全部转发到DB,DB瞬时压力过重雪崩
(3)缓存击穿(也成为缓存并发)
<1>单个key在缓存中查不到或者过期时间的key,去数据库查询
<2>若数据库数据量大并且是高并发的情况下可能会造成数据库压力过大而崩溃
<3>这里指的是单个key发生高并发!!!
(4)缓存击穿和缓存雪崩区别
<1>缓存击穿针对某一key缓存
<2>缓存雪崩针对的是很多key
<3>都是因为key值过期导致
2.缓存穿透、雪崩、击穿解决方案
(1)缓存穿透解决方案(2种)
第一种:采用布隆过滤器(推荐)
<1>将所有可能存在的数据哈希到一个足够大的bitmap中
<2>一个一定不存在的数据会被 这个bitmap拦截掉
<3>从而避免了对底层存储系统的查询压力
第二种:缓存空值并设置一个短的过期时间
<1>一个查询返回的数据为空,直接设置一个默认值存放到缓存
<2>第二次到缓冲中获取就有值了,而不会继续访问数据库
<3>它的过期时间会很短,最长不超过五分钟
<4>具体实现双重验证锁解决高并发环境下的缓存穿透问题
(2)扩展:布隆过滤器
<1>本质上布隆过滤器是一种set数据结构,比较巧妙的概率型数据结构
<2>当使用它的 contains 方法判断某个对象是否存在时,它可能会误判
<3>布隆过滤器说某个值存在时,这个值可能不存在;当说不存在时,那就肯定不存在
<4>特点是高效地插入和查询,占用空间更少
<5>缺点是其返回的结果是概率性的,而不是确切的
(3)缓存雪崩解决方案(4种)
<1>在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量(几乎不用)
<2>可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存
<3>不同的key,设置不同的过期时间,具体值可以根据业务决定,让缓存失效的时间点尽量均匀
<4>做二级缓存,或者双缓存策略(这种方式复杂点可忽略)
(4)缓存击穿解决方案(3种)
<1>通过synchronized+双重检查机制:某个key只让一个线程查询,阻塞其它线程
1.1.缺点: 会阻塞其它线程
1.2.在同步块中,继续判断检查,保证不存在,才去查DB
<2> 设置value永不过期
<3> 使用互斥锁(mutex key)
3.1. 业界比较常用的做法,是使用mutex
3.参考文档
https://zhuanlan.zhihu.com/p/91539644