击穿:指的是单个key在缓存中查不到,去数据库查询,数据库数据量大并且是高并发的情况下那么就可能会造成数据库压力过大而崩溃。
解决方案:
1,通过synchronized+双重检查机制:某个key只让一个线程查询,阻塞其它线程(缺点)。
2,设置value永不过期
3,使用互斥锁(mutex key)
雪崩:指的是多个key查询并且出现高并发,缓存中失效或者查不到,然后都去db查询,从而导致db压力突然飙升,从而崩溃。出现原因: 1 key同时失效 2 redis本身崩溃了。
方案:
1,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。(跟击穿的第一个方案类似,但是这样是避免不了其它key去查数据库,只能减少查询的次数)
2,可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存
3,不同的key,设置不同的过期时间,具体值可以根据业务决定,让缓存失效的时间点尽量均匀
4,做二级缓存,或者双缓存策略。A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期。(这种方式复杂点)
击透:一般是出现这种情况是因为恶意频繁查询才会对系统造成很大的问题: key缓存并且数据库不存在,所以每次查询都会查询数据库从而导致数据库崩溃。
解决方案:
1, 使用布隆过滤器: 热点数据等场景(具体看使用场景)
2, 将击透的key缓存起来,但是时间不能太长,下次进来是直接返回不存在,但是这种情况无法过滤掉动态的key,就是说每次请求进来都是不同额key,这样还是会造成这个问题
布隆过滤器是什么?
布隆过滤器可以理解为一个不怎么精确的 set 结构,当你使用它的 contains 方法判断某个对象是否存在时,它可能会误判。但是布隆过滤器也不是特别不精确,只要参数设置的合理,它的精确度可以控制的相对足够精确,只会有小小的误判概率。
当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就肯定不存在。打个比方,当它说不认识你时,肯定就不认识;当它说见过你时,可能根本就没见过面,不过因为你的脸跟它认识的人中某脸比较相似 (某些熟脸的系数组合),所以误判以前见过你。
缺点: 1 会存在一定的误判率
2 对新增加的数据无法进行布隆过滤
3 数据的key不会频繁的更改