缓存穿透、缓存雪崩、缓存击穿的概念及解决办法

一.缓存穿透:java

     缓存穿透是指查询一个必定不存在的数据,因为缓存是不命中时须要从数据库查询,查不到数据则不写入缓存,这将致使这个不存在的数据每次请求都要到数据库去查询,形成缓存穿透。数据库

     解决办法:数组

     1.布隆过滤缓存

  对全部可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃。还有最多见的则是采用布隆过滤器,将全部可能存在的数据哈希到一个足够大的bitmap中,一个必定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。并发

  补充:异步

      Bloom filter函数

  适用范围:能够用来实现数据字典,进行数据的判重,或者集合求交集性能

  基本原理及要点:对于原理来讲很简单,位数组+k个独立hash函数。将hash函数对应的值的位数组置1,查找时若是发现全部hash函数对应位都是1说明存在,很明显这个过程并不保证查找的结果是100%正确的。同时也不支持删除一个已经插入的关键字,由于该关键字对应的位会牵动到其余的关键字。因此一个简单的改进就是counting Bloom filter,用一个counter数组代替位数组,就能够支持删除了。添加时增长计数器,删除时减小计数器。spa

     2. 缓存空对象. 将 null 变成一个值.线程

  也能够采用一个更为简单粗暴的方法,若是一个查询返回的数据为空(不论是数 据不存在,仍是系统故障),咱们仍然把这个空结果进行缓存,但它的过时时间会很短,最长不超过五分钟。

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

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

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

 

 

二.缓存雪崩

    若是缓存集中在一段时间内失效,发生大量的缓存穿透,全部的查询都落在数据库上,形成了缓存雪崩。

    这个没有完美解决办法,但能够分析用户行为,尽可能让失效时间点均匀分布。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。

 

    解决方法

   1. java锁实现限流

 在缓存失效后,经过互斥锁来控制读数据库写缓存的线程数量。好比对某个key只容许一个线程查询数据和写缓存,其余线程等待。

 

    2.数据预热

  能够经过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存不一样的key,设置不一样的过时时间,让缓存失效的时间点尽可能均匀

 

     3.给缓存的失效时间,加上一个随机值,避免集体失效

 

     4.作二级缓存,或者双缓存策略。

     A1为原始缓存,A2为拷贝缓存,A1失效时,能够访问A2,A1缓存失效时间设置为短时间,A2设置为长期。

    咱们有两个缓存,缓存A和缓存B。缓存A的失效时间为20分钟,缓存B不设失效时间。本身作缓存预热操做。而后细分如下几个小点:

  I 从缓存A读数据库,有则直接返回
  II A没有数据,直接从B读数据,直接返回,而且异步启动一个更新线程。

  III 更新线程同时更新缓存A和缓存B。

 

      5.缓存永远不过时

 这里的“永远不过时”包含两层意思:

    (1) 从缓存上看,确实没有设置过时时间,这就保证了,不会出现热点key过时问题,也就是“物理”不过时。

     (2) 从功能上看,若是不过时,那不就成静态的了吗?因此咱们把过时时间存在key对应的value里,若是发现要过时了,经过一个后台的异步线程进行缓存的构建,也就是“逻辑”过时.

 从实战看,这种方法对于性能很是友好,惟一不足的就是构建缓存时候,其他线程(非构建缓存的线程)可能访问的是老数据,可是对于通常的互联网功能来讲这个仍是能够忍受。

 

缓存击穿

指的是热点key在某个特殊的场景时间内刚好失效了,刚好有大量并发请求过来了,形成DB压力。

解决办法

与缓存雪崩的解决方法相似: 用加锁或者队列的方式保证缓存的单线程(进程)写,在加锁方法内先从缓存中再获取一次,没有再查DB写入缓存。 

还有一种比较好用的(针对缓存雪崩与缓存击穿):

物理上的缓存是不设置超时时间的(或者超时时间比较长), 可是在缓存的对象上增长一个属性来标识超时时间(此时间相对小)。 当获取到数据后,校验数据内部的标记时间,断定是否快超时了,若是是,异步发起一个线程(控制好并发)去主动更新该缓存。

这种方式会致使必定时间内,有些请求获取缓存会拿到过时的值,看业务是否能接受而定。

相关文章
相关标签/搜索