参考https://juejin.im/post/5b604b9ef265da0f62639001
1. 缓存穿透
- 什么是缓存穿透
- 正常情况下,我们去查询数据都是存在。
- 那么请求去查询一条压根儿数据库中根本就不存在的数据,也就是缓存和数据库都查询不到这条数据,但是请求每次都会打到数据库上面去。
- 这种查询不存在数据的现象我们称为缓存穿透。
- 带来的问题
- 如果有黑客会对你的系统进行攻击,拿一个不存在的id 去查询数据,会产生大量的请求到数据库去查询。可能会导致你的数据库由于压力过大而宕掉。
- 解决:
- 缓存空值:
- 我们就可以为这些key对应的值设置为null 丢到缓存里面去。后面再出现查询这个key 的请求的时候,直接返回null 。
- BloomFilter(布隆过滤):
注:布隆过滤参考-----详解布隆过滤器- BloomFilter 类似于一个hbase set 用来判断某个元素(key)是否存在于某个集合中
- 在缓存之前在加一层 BloomFilter ,在查询的时候先去 BloomFilter 去查询 key 是否存在,如果不存在就直接返回,存在再走查缓存 -> 查 DB
- 如何选择:
- 针对于一些恶意攻击,攻击带过来的大量key 是不存在的,那么我们采用第一种方案就会缓存大量不存在key的数据。
- 针对这种key异常多、请求重复率比较低的数据,我们就没有必要进行缓存,使用第二种方案直接过滤掉。
- 而对于空数据的key有限的,重复率比较高的,我们则可以采用第一种方式进行缓存。
- 缓存空值:
2. 缓存雪崩
- 什么是缓存雪崩
- 缓存雪崩的情况是说,当某一时刻发生大规模的缓存失效的情况,比如你的缓存服务宕机了,会有大量的请求进来直接打到DB上面。结果就是DB 撑不住,挂掉。
- 解决
- 线程互斥:只让一个线程构建缓存,其他线程等待构建缓存的线程执行完,重新从缓存获取数据才可以,每个时刻只有一个线程在执行请求,减轻了db的压力,但缺点也很明显,降低了系统的qps(每秒查询率)
- 交错失效时间: 这种方法时间比较简单粗暴,既然在同一时间失效会造成请求过多雪崩,那我们错开不同的失效时间即可从一定长度上避免这种问题,在缓存进行失效时间设置的时候,从某个适当的值域中随机一个时间作为失效时间即可
3. 缓存击穿
- 什么是击穿
- 缓存击穿实际上是缓存雪崩的一个特例
- 击穿与雪崩的区别即在于击穿是对于特定的热点数据来说,而雪崩是全部数据
- 在平常高并发的系统中,大量的请求同时查询一个 key 时,此时这个key正好失效了,就会导致大量的请求都打到数据库上面去。这种现象我们称为缓存击穿。
- 会带来什么问题
- 会造成某一时刻数据库请求量过大,压力剧增。
- 解决:
- 二级缓存:对于热点数据进行二级缓存,并对于不同级别的缓存设定不同的失效时间,则请求不会直接击穿缓存层到达数据库。
- 这里参考了阿里双11万亿流量的缓存击穿解决方案,解决此问题的关键在于热点访问。由于热点可能随着时间的变化而变化,针对固定的数据进行特殊缓存是不能起到治本作用的,结合LRU算法能够较好的帮我们解决这个问题。