引言
要了解缓存的这几个相关问题,我们先以一个例子来引入:
有一个get请求:
api/news/getById/1
正常情况下对其申请访问的流程如图:
但若是如此,访问增多或者受到攻击时很容易受到以下问题
1 缓存穿透
1.1 造成原因
当查询一个不存在的数据时,MySQL查询不到数据,也不会直接写入缓存,导致每次请求都会查询数据库
1.2 解决方案
1.2.1 方案一 缓存空数据
缓存空数据,查询返回的数据为空,仍将该结果保存,也就是保存null数据
优点:简单
缺点:消耗内存,且当数据库中的数据更新后,可能使得缓存与数据库中的数据不一致
1.2.2 方案二 布隆过滤器
先解释一个概念:bitmap(位图)
bitmap相当于一个以bit为单位组成的数组,每个单元只能存储二进制数0或1
布隆过滤器作用:检索一个元素是否在一个集合中
比如:
但是当数组大小有限时,就会出现类似哈希冲突的问题:
此时可以发现,如果id为3的数据不存在时,用布隆过滤器时会造成误判
可以得出,数组越大,布隆过滤器误差越小,但同时带来更多的内存消耗
如何调整其误判率呢?
可以通过Redisson或者Guava来设置误判率,通常将误判率设置在5%以下
2 缓存击穿
2.1 造成原因
给某个key设置了过期时间,当该key过期时,恰好对其有大量并发请求,这些并发请求可能瞬间将数据库压垮
2.2 解决方案
2.2.1 方案一 互斥锁
特点:数据强一致,性能差,可在银行系统中使用
2.2.2 方案二 逻辑过期
特点:高可用,但不能保证数据完全一致
性能优,可在秒杀功能中使用
3 缓存雪崩
3.1 造成原因
同一时段大量key同时失效或Reids服务器宕机,导致大量请求到达数据库,给数据库带来巨大压力
3.2 解决方案
1.给不同key的TTL添加随机值
2.利用Redis集群提高服务可用性,如哨兵模式和集群模式
3.给缓存业务添加降级限流策略,如nginx或spring cloud gateway
4.给业务添加多级缓存,如Guava或Caffeine
给缓存业务添加降级限流策略可作为保底策略,穿透、击穿、雪崩均适用