图解缓存穿透与缓存雪崩

缓存

常见的数据库,比如oracle、mysql等,数据都是存放在磁盘中。为了提高查询速度,减轻数据库压力,当我们查询数据时,先去查询缓存,若果缓存中查询不到,再去查询数据库。数据库一般内部自带的有缓存机制,初次之外也有外部缓存,如redis.
在这里插入图片描述

缓存穿透

一、何为缓存穿透

正常情况下,我们去缓存中查询数据,有一定几率查询失败,这时就要数据库查询,如果直接去查询一条缓存中和数据库中都不存在的数据,那么这个查询就会百分之百查询到数据库上去。

这种查询称为缓存穿透,因为去缓存中查询一定会失败,所以请求就会打到数据库上。

缓存穿透带来的问题

如果有人恶意拿一个不存在的数据去查询,会产生大量请求,这些请求最终会打到数据库中,数据库可能因为承受不住压力而宕机。

解决方案

1.缓存空值

碰到查询结果为空的键,放一个空值在缓存中,下次再访问就立刻知道这个键无效,不用查询数据库了

但是这个方法并不完美:
第一,缓存空值需要更多的内存空间,我们可以设置一个比较短的过期时间,过了这个时间,自动剔除这个空值的缓存。此外空值应该与正常值分开存放,否则当空间不足的时候,缓存系统可能有优先剔除正常值,再剔除空值,这个漏洞可能会被攻击。
第二,如果某个key在缓存中记录为空值,过了一段时间,数据库中添加了这个key,那此时需要利用某种方式来清除这个空值。如果使用的是redis缓存,更新数据后直接在redis中清除即可。

2.BloomFilter(布隆过滤器)

简单来讲,布隆过滤器是一种数据结构,布隆过滤器可以用来告诉你某样东西"一定不存在或者可能存在"。关于布隆过滤器更多细节,这里不再赘述。我们在缓存之前加一个布隆过滤器,查询的时候先去布隆过滤器中查询key是否存在,如果不存在就直接返回,如果key可能存在,再去缓存中查询。
流程如下:
在这里插入图片描述

二、缓存雪崩

当某一时刻发生大规模的缓存失效的情况,会有大量的请求进来直接冲到数据库上面。结果就是数据库扛不住,直接挂掉。

解决方案

  1. 使用集群缓存,保证缓存服务高可用。
  2. 使用Hystrix限流(Hystrix 是一个 java 依赖隔离工具,它帮助我们管理线程池,让每种资源都单独运行在自己的线程池中)。

热点数据集中失效问题

上面提到,我们一般会给某个数据在缓存中设置一个失效时间,过了这个时间,缓存中的数据就失效。当有请求再次查询这个数据时,系统会先查询数据库,然后重建缓存。如图所示:
在这里插入图片描述

但是对于一些热点的数据来说(比如两个明星突然公开恋情),假设某个时刻缓存失效,而后续还会存在大量的请求过来,所以系统会重建缓存,但重建该缓存可能需要的时间比较久,这就会导致会有大量线程来重建缓存,造成系统后端压力过大,从而导致宕机。如图所示:
在这里插入图片描述

解决方案

  1. 使用互斥锁,这种方式只允许一个线程来重建缓存,先将其他请求阻塞,等到缓存重建完毕,再重新去缓存中查询。这种方法比较简单,但是可能会存在死锁和线程池阻塞的风险。如图所示:
    在这里插入图片描述
  2. 不再设置过期时间,也就是说缓存中的数据不会"到期就失效",同时设置一个"逻辑过期时间",过了这个"逻辑过期时间"启动一个线程去数据库中查询最新的内容,然后更新缓存中的值。
    这样从根本上杜绝了热点数据失效的问题,但是唯一不足的就是,数据的一致性无法保证。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值