一、缓存穿透
缓存穿透是指查询一个不存在的数据,由于缓存中没有,所以每次请求都会穿透到数据库,导致数据库压力过大,甚至宕机。
解决方法:
1. 布隆过滤器:将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力。
2. 缓存空对象:如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过 5 分钟。
3. 接口层增加校验:对于一些可能存在攻击的接口,可以在接口层增加校验,比如用户鉴权、参数校验等。
二、缓存击穿
缓存击穿是指一个存在的 key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到数据库上,造成短时间内数据库压力过大。
解决方法:
1. 设置热点数据永不过期:对于一些热点数据,可以设置永不过期,这样就不会出现缓存过期的情况。
2. 加互斥锁:对于缓存失效的时候,不同的请求都会同时查询数据库,可以使用互斥锁来保证只有一个请求查询数据库,其他请求等待查询结果。
3. 使用队列:将请求放入队列中,由一个线程去查询数据库,其他线程等待查询结果。
三、应对方法
1. 采用多级缓存:将缓存分为多级,如本地缓存、分布式缓存、数据库缓存等,这样可以减少缓存穿透和缓存击穿的概率。
2. 合理设置缓存过期时间:对于不同的数据,可以设置不同的缓存过期时间,热点数据可以设置永不过期,冷门数据可以设置较短的过期时间。
3. 预热缓存:在系统启动时,可以将一些热点数据预先加载到缓存中,避免缓存失效时出现缓存击穿的情况。
4. 限流降级:对于一些高并发的接口,可以采用限流降级的方式,限制请求的并发数,或者在缓存失效时返回默认值,避免对数据库造成过大的压力。