看完这篇缓存穿透的文章,保证你能和面试官互扯!!!

前言

  • 昨天有读者朋友留言,想要陈某写一篇防止缓存穿透的文章,今天特地写了一篇。面试

  • 文章目录以下:算法

什么是缓存穿透?

  • 缓存穿透实际上是指从缓存中没有查到数据,而不得不从后端系统(好比数据库)中查询的状况。sql

  • 缓存毕竟是在内存中,不可能全部的数据都存储在 Redis 中,所以少许的缓存穿透是不可避免的,也是系统可以承受的,可是一旦在瞬间发生大量的缓存穿透,数据库的压力会瞬间增大,后果可想而知。数据库

  • 在开发中使用缓存的方案以下图,在查询数据库以前会先查询 Redis:后端

  • 缓存穿透的整个过程分为以下几个步骤:数组

  1. 应用查询缓存,缓存不命中缓存

  2. DB 层不命中,不将空结果缓存性能优化

  3. 返回空结果ide

  4. 下一个请求继续重复1,2,3步。
    性能

解决方案

  • 万事万物都是相生相克,既然出现了缓存穿透,就必定有避免的方案。

  • 下面介绍两种缓存的方案,分别是缓存空值布隆过滤器

缓存空值

  • 回顾缓存穿透的定义知道,大量空值没有缓存致使重复的访问 DB 层,由此解决方案也是很明显了,直接将返回的空值也缓存便可。此时的执行步骤以下图:

  • 如上图所示,若是缓存不命中,查询 DB 层以后,直接将空值缓存在 Redis 中。伪代码以下:

Object nullValue = new Object();
try {
  Object valueFromDB = getFromDB(uid); //从数据库中查询数据
  if (valueFromDB == null) {
    cache.set(uid, nullValue, 10);   //若是从数据库中查询到空值,就把空值写入缓存,设置较短的超时时间
  } else {
    cache.set(uid, valueFromDB, 1000);
  }
} catch(Exception e) {
  // 出现异常也要写入缓存
  cache.set(uid, nullValue, 10);
}
  • 经过伪代码能够很清楚的了解了缓存空值的流程,可是须要注意如下问题:

    • 缓存必定要设置过时时间:由于空值并非准确的业务数据,而且会占用缓存空间,因此要给空值加上一个过时时间,使得可以在短时间以内被淘汰。可是随之而来的一个问题就是在必定的时间窗口内缓存的数据和实际数据不一致,好比设置 10 秒钟过时时间,可是在这 10 秒以内业务又写入了数据,那么返回就不该该为空值了,因此还要考虑数据一致的问题,解决方法很简单,利用消息系统或者主动更新的方式清除掉缓存中的数据便可。

布隆过滤器

  • 1970 年布隆提出了一种布隆过滤器的算法,用来判断一个元素是否在一个集合中。这种算法由一个二进制数组和一个 Hash 算法组成。

  • 具体的算法思想这里再也不详细解释了,若有不了解的能够看陈某上一篇文章大白话布隆过滤器,又能和面试官扯皮了~

  • 解决缓存穿透的大体思想:在访问缓存层和存储层以前,能够经过定时任务或者系统任务来初始化布隆过滤器,将存在的 key 用布隆过滤器提早保存起来,作第一层的拦截。例如:一个推荐系统有 4 亿个用户 id, 每一个小时算法工程师会根据每一个用户以前历史行为计算出推荐数据放到存储层中, 可是最新的用户因为没有历史行为, 就会发生缓存穿透的行为, 为此能够将全部推荐数据的用户作成布隆过滤器。若是布隆过滤器认为该用户 id 不存在, 那么就不会访问存储层, 在必定程度保护了存储层。此时的结构以下图:

  • 固然布隆过滤器的假阳性的存在致使了误判率,可是咱们能够尽可能的下降误判率,一个解决方案就是:使用多个 Hash 算法为元素计算出多个 Hash 值,只有全部 Hash 值对应的数组中的值都为 1 时,才会认为这个元素在集合中。

  • 这种方法适用于数据命中不高数据相对固定实时性低(一般是数据 集较大)的应用场景,代码维护较为复杂,可是缓存空间占用少。为何呢?由于布隆过滤器不支持删除元素,一旦数据变化,并不能及时的更新布隆过滤器。

两种方案对比

  • 两种方案各有优缺点,具体使用哪一种方案仍是要根据业务场景和系统体量来定。具体的区别以下表:

方案 适用场景 维护成本
缓存对象 1. 数据命中不高 2. 数据频繁变化,实时性高 代码维护简单、须要过多的缓存空间,数据一致性须要本身实现
布隆过滤器 1. 数据命中不高 2.数据相对固定,实时性低 代码维护复杂、缓存空间占用少

总结

  • 至此,如何解决缓存穿透的问题已经介绍完了,以为写得不错的,有所收获的朋友,点点在看,分享关注一波。

  • 最近很多读者留言陈某但愿我多发一些面试题,这几天正好在整理大厂面试常问的面试题,后面会陆续发布,已经发布的面试题有两篇,分别是【吊打面试官】Mysql 大厂高频面试题!!!Redis 高频面试题及答案。关注陈某,天天都会有面试题更新!

文章留言区

往期推荐

【吊打面试官】Mysql大厂高频面试题!!!

Redis高频面试题及答案

大白话布隆过滤器,又能和面试官扯皮了~

每天用Redis,持久化方案有哪些你知道吗?

Mysql性能优化:为何count(*)这么慢? Mysql性能优化:如何给字符串加索引? Mysql中的三类锁,你知道吗?

每天写 order by,你知道Mysql底层执行流程吗?