1. 缓存穿透
ps:这是我的个认笔记地址:TinkerBell学习笔记
1.1 现象:
-
该资源,redis没有,mysql等数据库中也没有,所以每次针对该key都不存在,直接杀到了数据源,导致数据源挂了
-
正常业务场景少见 多为黑客攻击网站常见手段
1.2 造成的条件:
-
应用服务器压力变大,访问请求增加
-
redis 命中率下降(重点)
-
导致一直访问查询数据库
服务器压力变大,请求太多,导致redis缓存命中率开始下降,对数据库的访问越来越多,数据库最终承受不住压力,崩溃了。
1.3 如何解决
-
对空值缓存
- 如果一个查询返回的数据为空(不管是数据是否不存在),仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟。
-
设置可访问的名单(白名单)
- 使用 bitmaps 类型定义一个可以访问的名单,名单 id 作为 bitmaps 的偏移量,每次访问和 bitmap 里面的 id 进行比较,如果访问 id 不在 bitmaps 里面,进行拦截,则不允许访问。
-
采用布隆过滤器
-
布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量(位图)和一系列随机映射函数(哈希函数)。(跟bitmaps类似,不过效率更高)
-
布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难,命中率不一定高。
-
将所有可能存在的数据哈希到一个足够大的 bitmaps 中,一个一定不存在的数据会被这个 bitmaps 拦截掉,从而避免了对底层存储系统的查询压力。
-
-
进行实时监控
- 当发现 Redis 的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务。
2. 缓存击穿
注意与缓存穿透的区别:
- 缓存穿透
- redis命中率下降,导致数据库访问量激增
- 缓存击穿
- redis正常访问,但某个热点key突然失效,导致瞬间数据库的访问量激增
2.1 现象
key 对应的数据存在,但在 redis 中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB 加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端 DB 压垮。
-
数据库访问压力瞬间增大
-
redis 中没有出现大量 key 过期,redis 正常运行(与缓存穿透的区别)
-
某个经常访问的 key,即十分热点的key,不停地被大量访问,当这个key过期的瞬间,持续的高并发就击穿了缓存,大量请求数据库,导致数据库奔溃
2.2 如何解决
-
预先设置热门数据
-在 redis 高峰访问之前,把一些热门数据提前存入到 redis 里面,加大这些热门数据 key 的时长。
-
实时调整
- 现场监控哪些数据热门,实时调整 key 的过期时长。
-
使用锁
- 对请求加锁,如果获取不到资源,一直等待,直到获取资源释放锁,不建议采用,数据源压力得到缓解,性能大幅度降低
3. 缓存雪崩
3.1 现象
-
key 对应的数据存在,但在 redis 中过期,此时若有大量并发请求过来,这些请求发现缓存过期后,一般都会从后端 DB 加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端 DB 压垮。
-
缓存雪崩与缓存击穿的区别在于这里针对很多 key 缓存,前者则是某一个 key。
-
数据库压力变大
-
极少的时间段,查询大量 key 的集中过期情况(大量key集中过期,而缓存击穿是热点key过期)
-
3.2 如何解决
-
构建多级缓存架构
- nginx 缓存 + redis 缓存 + 其他缓存(ehcache等)
-
使用锁或队列:
- 用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。不适用高并发情况。
-
设置过期标志更新缓存:
- 记录缓存数据是否过期(设置提前量),快过期的时候,提前进行一个缓存。如果过期会触发通知另外的线程在后台去更新实际 key 的缓存。
-
将缓存失效时间分散开:
- 比如我们可以在原有的失效时间基础上增加一个随机值,比如 1~5 分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。