二、常见缓存失效问题及解决方案
在缓存中常常会被提到问题:缓存穿透、缓存击穿、缓存雪崩。 下面我们就简单解释一下它们是什么以及如何解决?
缓存穿透: 指的是当访问实际不存在的数据时,该请求全部都打到数据库上面,导致缓存失效。
解决方案:缓存空对象、布隆过滤器
- 缓存空对象:
- 流程:对未查到的数据也进行缓存,以减少对数据库的缓存
- 优点:实现简单,便于维护
- 存在问题:导致内存的消耗以及可能出现短期的不一致,可通过TTL解决
- 布隆过滤器: 可理解为一个byte[] 里面存储的是二进制数据,也就是将数据库里面的数据通过特定的hash算法得到的hash值存储到布隆过滤器中,布隆过滤器只需要查找某个位置的值是0还是1就可以知道数据是否存在。
- 过程:首先请求会来到布隆过滤器,如果存在就会则放行,走缓存和数据,如果不存在就直接拒绝
- 优点:内存占用少,没有多余的存储key
- 存在问题:布隆过滤器的结果可能不正确,仍然存在穿透风险,但是需要知道的一点是布隆过滤器的结果说数据存在就不一定正确,但是不存在那么一定正确。
上面的两种方案其实还是属于被动的方案,我们其实还可以做一些主动的方案:
- 增强id的复杂度,避免攻击者猜到id的规律,通过数据基础格式的校验来防止
- 加强用户权限校验,比如什么用户可以访问,需要登录,用户的访问频率
- 也可以做好热点参数的限流,比如有些内容访问比较多,就限流
缓存雪崩: 指的是大量的key同时失效或者redis服务端宕机,导致大量的请求打到数据库,造成服务器压力
解决方案:随机过期时间、多级缓存、集群或者哨兵提高服务的可用性、给缓存添加降级限流策略
这块的内容大概的讲解一下:随机过期时间,在TTL中添加随机值,多级缓存可以利用浏览器,nginx,jvm来缓存数据。集群主要是针对redis在三高中出现宕机,通过主从来实现服务的高可用和稳定。而限流降级针对的是服务全挂(机房断电),通过拒绝服务让其不用打到数据库
缓存击穿: 指的是热点key失效,导致大量请求打到数据库上
解决方案:互斥锁、逻辑过期
- 互斥锁:让一个请求拿到锁,去数据库查询数据,然后写回缓存,需要注意的是没有拿到锁的请求不能一种去获得锁,需要休眠一会。其余请求只能等待,性能较差
- 逻辑过期:只是在redis中不设置过期,但是这样就会导致数据会不一致,那么我们就需要通过设置逻辑过期来进行解决该问题