非关系型数据库 八股文 Redis相关 缓存雪崩 击穿 穿透
目录
图
缓存雪崩
大量数据同时过期解决方案
也有可能是 Redis 挂了 故障
缓存击穿
用互斥锁解决
热点数据永远不过期
缓存穿透 重点
可能的原因
限制 请求的 访问
缓存空值或者默认值
布隆过滤器(重要)
总结
参考资料
图
缓存雪崩
缓存雪崩是指大量缓存数据同时过期
所以我们通常会给 redis 里面的数据随机化过期时间 当缓存数据过期后 用户请求数据 数据不在缓存里 就会重新生成缓存 后续的请求就能直接访问缓存
如果数据大规模过期 用户请求就会全去 mysql mysql 承受不了就会宕机 进而导致整个系统崩溃
redis 故障也会导致缓存雪崩
大量请求也会到 mysql 去
大量数据同时过期解决方案
- 随机化过期时间
设置缓存数据过期时间随机 用 伪随机数 设置时间
- 互斥锁
互斥锁 这个做法是如果发现 redis 没有数据 加一个互斥锁 则在同一时间内 只让一个线程去构建缓存 这样就不用所有请求都到 mysql 了 当这个线程构建缓存结束后 释放锁 其他线程的请求此时就会进来 获取新的缓存
- 异步处理
可以让缓存一直存在 即使过期了 也很快更新 我们可以设置一个定时任务 在后台检测缓存是否存在 如果不存在则更新 尽量保证每次用户访问数据的时候 缓存都是存在的 同样的我们也可以使用消息队列 业务线程发现缓存失效 通过消息队列发一条消息通知后台线程更新缓存
- 缓存预热
我们在业务上线的时候 最好进行缓存预热 先把缓存加载起来
也有可能是 Redis 挂了 故障
- 服务熔断 请求限流
redis 挂了则直接返回错误 不要访问数据库 但这样会让业务无法工作
限流也可以 请求太多了就直接拒绝服务 直到正常
- 构建集群
构建 redis 集群
缓存击穿
假设我们有热点数据
在高并发场景下获取热点数据
热点数据过期的一瞬间 大量高并发请求会直接到 mysql
然后系统就挂了
我感觉缓存击穿是缓存雪崩的一个子集
用互斥锁解决
还是在业务线程请求数据的时候 如果发现缓存里没有数据 就加上互斥锁 保证此时间只有业务线程去数据库获取数据再回来更新缓存 然后释放锁 让其他线程去拿缓存里的数据
如果未能拿到互斥锁的请求 要不返回空值 要不继续等
热点数据永远不过期
永不过期
如果数据库数据更新了再通知缓存
可以用消息队列实现
缓存穿透 重点
之前我们说的是 缓存雪崩 缓存击穿 这两种情况
那么说明还是有数据的 我们只是要求缓存恢复相对应的数据 即可正常运行
但是如果 数据库没有数据 缓存也没有数据
后续的请求依旧会全部到达缓存 导致数据库压力骤增
为什么会存在 数据库中也没有数据 缓存中也没有数据这种情况呢
可能的原因
- 业务误操作 删掉了 mysql 和缓存里面的数据
- 黑客恶意攻击 特地访问不存在的数据
限制 请求的 访问
在 API 的入口处我们要判断请求参数是否合理
请求参数是否包含非法值 是否存在
让恶意请求不会到达数据库和缓存 直接被拦截
缓存空值或者默认值
当我们线上业务发现存在缓存穿透
可以在缓存里面提前设置一个空值或者是默认值
这样后续请求到达缓存的时候就能读取空值或者默认值 返回给应用
而不会继续查询数据库
布隆过滤器(重要)
布隆过滤器是一个位数组
通过 k 个函数对数据进行哈希计算
得到 k 个结果
然后将结果作为索引
将对应索引处的值标记为 1
数据传入同样是进行 k 个哈希运算
如果这 k 个位置的数值都是 1 那么表示数据已经出现过了
布隆过滤器主要反馈的是两个信息
- 数据可能出现过 (因为可能会存在哈希冲突)
- 数据一定没有出现
布隆过滤器说数据存在 可能存在 也可能不存在
但是布隆过滤器说数据不存在 那就是不存在
进入缓存查数据的时候 在要进入数据库查询数据返回更新缓存的时候 我们可以使用布隆过滤器查看数据库中是否存在数据
总结
参考资料
什么是缓存雪崩、击穿、穿透? | 小林coding