Redis的缓存穿透、缓存击穿、缓存雪崩、热点数据失效问题及解决方案(转)

时间:2021-08-20
本文章向大家介绍Redis的缓存穿透、缓存击穿、缓存雪崩、热点数据失效问题及解决方案(转),主要包括Redis的缓存穿透、缓存击穿、缓存雪崩、热点数据失效问题及解决方案(转)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

转:https://zhuanlan.zhihu.com/p/152223694

 ​ 在我们的平常的项目中多多少少都会使用到缓存,因为一些数据我们没有必要每次查询的时候都去查询到数据库。特别是高 QPS 的系统,每次都去查询数据库,对于你的数据库来说将是灾难。但缓存使用不当,也会引起灾难。

缓存穿透

什么是缓存穿透

​ 正常情况下,我们去查询的数据都是存在。但如果请求去查询一条数据库根本就不存在的数据,也就是缓存和数据库都查询不到这条数据,但是请求每次都会打到数据库上面去。这种查询不存在数据的现象称为缓存穿透。

缓存穿透带来的问题

​ 如果有黑客对你的系统进行攻击,拿一个不存在的id 去查询数据,会产生大量的请求到数据库中,可能会导致你的数据库由于压力太大而宕机。

解决方案

1、缓存空值

​ 之所以会穿透,是因为缓存中没有存储这些空数据的key,从而导致每次查询都到数据库去了。因此我们可以为这些key对应的值设置null丢到缓存里面去,后面再出现查询这个key的请求的时候,就直接返回null。不过要设置过期时间。

2、布隆过滤器

​ 这种方式在大数据场景应用比较多,比如Hbase中使用它去判断数据是否在磁盘上,还有在爬虫场景判断URL是否已经被爬取。

​ 这种方案可以加在第一种方案中,在缓存之前再加一层布隆过滤器,在查询的时候先去布隆过滤器查询key是否存在,如果不存在就直接返回,存在再走查缓存和数据库。

3、用户鉴权

​ 这种情况有可能是黑客进行恶意攻击,因此我们可以在系统中增加用户鉴权校验或者在接口层增加校验,直接拦截不正常的请求。

方案选择

​ 对于一些恶意攻击,攻击带过来的大量的key是不存在的,那么我们采用第一种方案就会缓存大量不存在key的数据,此时第一种方案就不合适了,我们可以先使用第二种方案过滤掉这些key。即针对这种key异常多、请求重复率比较低的数据,我们没有必要进行缓存,使用第二种方案直接过滤掉。

缓存击穿

什么是缓存击穿

​ 在平常高并发的系统中,大量的请求同时查询一个key时,此时这个key刚好失效了,就会导致大量的请求打到数据库上面去,这种现象我们成为缓存击穿。

缓存击穿带来的问题

​ 会造成某一时刻数据库请求里过大,压力剧增。

解决方案

1、设置热点数据永不过期

2、加互斥锁

​ 多个线程同时去查询数据库的这条数据时,我们可以在第一个查询数据的请求上使用一个互斥锁来锁住它,其他线程走到这一步拿不到锁就等着,等第一个线程查询到了数据,然后做缓存。后面的线程进来了,就可以直接走缓存了。

缓存雪崩

什么是缓存雪崩

​ 缓存雪崩的情况是,在某一时刻发生大规模的缓存失效的情况,比如你的缓存服务宕机了,会有大量的请求进来直接打到DB上。结果就是DB撑不住宕机了。

解决方案

1、事前,使用集群缓存,保证缓存服务的高可用

​ 这种方案是在发生雪崩前对缓存集群实现高可用,如果是使用Redis,可以使用 主从+哨兵或者Redis Cluster来避免Redis全盘崩溃的情况。

2、事中:ehcache本地缓存 + Hystrix限流&降级,避免数据库被打死

​ 使用ehcache本地缓存的目的也是考虑在Redis Cluster完全不可用的时候,ehcache本地缓存可以支撑一阵。

​ 使用Hystrix进行限流&降级,例如一秒来了3000个请求,我们可以设置只能有一秒1000个请求能通过这个组件,那么其他剩余的2000请求就会走限流逻辑。然后去调用我们自己开发的降级组件,比如设置一些默认值之类的,以此来保护数据库不会被大量的请求给打死。

3、事后:开启Redis持久化机制,尽快恢复缓存集群

​ 一旦重启,就能从磁盘上自动加载数据恢复内存中的数据。

解决热点数据集中失效问题

什么是热点数据集中失效

​ 我们在设置缓存的时候,一般会给缓存设置一个失效时间,过了这个时间,缓存就失效。对于一些热点的数据来说,当缓存失效以后会存在大量的请求过来,然后打到数据库中去,从而可能导致数据库崩溃的情况。

解决方案

1、设置不同的过期时间

​ 为了避免这些热点数据集中失效,那么我们在设置缓存过期时间的时候,尽量让他们失效的时间错开。例如在一个基础的时间上加上或减去一个范围内的随机值。

2、互斥锁

​ 结合上面击穿的情况,在第一个请求去查询数据库的时候加一个互斥锁,其余的查询都会被阻塞住,知道锁释放,从而保护数据库。

​ 但是因为它会阻塞其他线程,此时系统吞吐量会下降,需要结合实际的业务去考虑是否要这么做。

原文地址:https://www.cnblogs.com/running-life-it/p/15166453.html