关于缓存穿透,缓存击穿,缓存雪崩,热点数据失效问题的解决方案(转)

1.咱们使用缓存时的业务流程大概为:

当咱们查询一条数据时,先去查询缓存,若是缓存有就直接返回,若是没有就去查询数据库,而后返回。这种状况下就可能出现下面的一些现象。mysql

2.缓存穿透

2.1什么是缓存穿透

缓存穿透是指查询一个必定不存在的数据,因为缓存是不命中时被动写的,而且出于容错考虑,若是从存储层查不到数据则不写入缓存,这将致使这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击咱们的应用,这就是漏洞。redis

2.2缓存穿透带来的问题

试想一下,若是有黑客对你的系统进行攻击,拿一个不存在的id去查询数据,会产生大量的请求到你的数据库去查询,可能会致使你的数据库因为压力过大而宕掉。sql

2.3解决的办法

2.3.1缓存空值

之因此会发生穿透,就是由于缓存中没有储存这些空数据的key。从而致使每次查询都到数据库去了。数据库

那么咱们就能够为这些key对应的值设置为null丢到缓存里面去。后面出现查询这个key的请求的时候直接返回null。缓存

这样就不用再到数据库中去走一圈了,可是别忘了设置过时时间。并发

缓存空对象会有两个问题:分布式

第一,空值作了缓存,意味着缓存层中存了更多的键,须要更多的内存空间 ( 若是是攻击,问题更严重 ),比较有效的方法是针对这类数据设置一个较短的过时时间,让其自动剔除。高并发

第二,缓存层和存储层的数据会有一段时间窗口的不一致,可能会对业务有必定影响。例如过时时间设置为 5分钟,若是此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时能够利用消息系统或者其余方式清除掉缓存层中的空对象。大数据

2.3.2用布隆过滤器BloomFilter

BloomFilter相似于一个hbase set用来判断某个元素(key)是否存在于某个集合中。url

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

这种方案能够加在第一种方案中,在缓存以前加一层BloomFilter,在查询的时候先去BloomFilter去查询key是否存在,若是不存在就直接返回,存在再去查缓存-------->差数据库。

流程图以下:

2.4如何选择

针对于一些恶意攻击,攻击带来大量key是不存在的,那么咱们采用第一种方案就会缓存大量不存在的数据。此时咱们采用第一种方案就不合适了,咱们彻底能够先使用第二种方案过滤掉这些key。

针对这些key异常多,请求多,重复率比较低的数据,咱们就没有必要进行缓存,使用第二种方案直接过滤掉。

而对于空数据的key有限的,重复率比较高的,咱们则能够采用第一种方式进行缓存。

3.缓存击穿

3.1什么是缓存击穿

缓存击穿是咱们使用缓存可能遇到的第二个问题。

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

3.2会带来什么问题

会形成某一时刻数据请求量过大,压力剧增。

3.3如何解决

上面现象是多个线程同时去查询数据库的这一条数据,那么咱们能够在第一个查询数据的请求上使用一个互斥锁来锁住它。(若是是单机,能够用synchronized或者lock来处理,若是是分布式环境能够用分布式锁就能够了(分布式锁,能够用memcache的add, redis的setnx, zookeeper的添加节点操做))

其余线程走到这一步拿不到锁就等着,等待第一个线程查询到了数据,而后作缓存。后面的线程进来发现已经有了缓存,就直接走缓存。

4.缓存雪崩

4.1什么是缓存雪崩

缓存雪崩的状况是指:当某一时刻发生大规模的缓存失效的状况,好比你的缓存服务宕机了,会有大量的请求进来直接打到数据库上面,结果就是数据库挂掉。

4.2解决办法

4.2.1雪崩前:使用集群缓存,保证缓存服务的高可用

这种方案就是在发生雪崩前对缓存集群,实现高可用,若是是使用Redis,可使用(主从 + 哨兵),Redis Cluster来避免Redis全盘崩溃的状况。

4.2.2雪崩中:ehcache本地缓存 + Hystrix限流 & 降级,避免MySQl被打死

使用ehcache本地缓存的目的也是考虑Redis Cluster彻底不可用的时候,ehcache本地缓存还可以支撑一阵。

使用Hystrix进行限流 & 降级,好比一秒来了5000个请求,咱们能够设置假设一秒只能有2000个请求能够经过这个组件,那么其余剩余的3000请求就会走限流逻辑。

而后去调用咱们本身开发的降级组件(降级),好比设置的一些默认值等等之类的。以此来保护最后的MySQl不会被大量的请求打死。

4.2.3雪崩后:开启Redis持久化,尽快恢复缓存集群。

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

咱们在设置缓存的时候,通常会给缓存设置一个失效的时间,过了这个时间,缓存就失效了。

对于一些热点数据来讲,当缓存失效后会存在大量的请求到数据库上来,从而可能致使数据库崩溃的状况。

5.1解决办法

5.1.1设置不一样的失效时间

为了不这些热点数据集体失效,那么咱们在设置缓存过时时间的时侯,让他们失效的时间错开。好比咱们能够在原有的失效时间基础上增长一个随机值。

5.1.2互斥锁

结合上面的击穿状况,在第一个请求去查询数据库的时候对它加一个互斥锁,其他的查询请求都会被阻塞住,直到锁被释放,从而保护数据库。

可是也是因为它会阻塞其余线程,此时系统的吞吐量会降低。须要结合实际业务去考虑。

相关文章
相关标签/搜索