看完这篇缓存穿透的文章,又能和面试官互扯了~[亲测有效]

看完这篇缓存穿透的文章,又能和面试官互扯了~[亲测有效]前言 昨天有读者朋友留言,想要陈某写一篇防止缓存穿透的文章,今天特意写了一篇。 文章目录如下: 什么是缓存穿透? 缓存穿透其实是指从缓存中没有查到数据,而不得不从后端系统(比如数据库)中查询的情况。

看完这篇缓存穿透的文章,又能和面试官互扯了~

前言

  • 昨天有读者朋友留言,想要陈某写一篇防止缓存穿透的文章,今天特意写了一篇。 看完这篇缓存穿透的文章,又能和面试官互扯了~[亲测有效]
  • 文章目录如下:
  • 看完这篇缓存穿透的文章,又能和面试官互扯了~[亲测有效]

什么是缓存穿透?

  • 缓存穿透其实是指从缓存中没有查到数据,而不得不从后端系统(比如数据库)中查询的情况。
  • 缓存毕竟是在内存中,不可能所有的数据都存储在 Redis 中,因此少量的缓存穿透是不可避免的,也是系统能够承受的,但是一旦在瞬间发生大量的缓存穿透,数据库的压力会瞬间增大,后果可想而知。
  • 在开发中使用缓存的方案如下图,在查询数据库之前会先查询 Redis: Redis缓存
  • 缓存穿透的整个过程分为如下几个步骤:
    1. 应用查询缓存,缓存不命中
    2. DB 层查询不命中,不将空结果缓存
    3. 返回空结果
    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); }

代码100分

代码100分 
  • 通过伪代码可以很清楚的了解了缓存空值的流程,但是需要注意以下问题:
    • 缓存一定要设置过期时间:因为空值并不是准确的业务数据,并且会占用缓存空间,所以要给空值加上一个过期时间,使得能够在短期之内被淘汰。但是随之而来的一个问题就是在一定的时间窗口内缓存的数据和实际数据不一致,比如设置 10 秒钟过期时间,但是在这 10 秒之内业务又写入了数据,那么返回就不应该为空值了,所以还要考虑数据一致的问题,解决方法很简单,利用消息系统或者主动更新的方式清除掉缓存中的数据即可。

布隆过滤器

  • 1970 年布隆提出了一种布隆过滤器的算法,用来判断一个元素是否在一个集合中。这种算法由一个二进制数组和一个 Hash 算法组成。
  • 具体的算法思想这里不再详细解释了,如有不了解的可以看陈某上一篇文章大白话布隆过滤器,又能和面试官扯皮了~
  • 解决缓存穿透的大致思想:在访问缓存层和存储层之前,可以通过定时任务或者系统任务来初始化布隆过滤器,将存在的 key 用布隆过滤器提前保存起来,做第一层的拦截。例如:一个推荐系统有 4 亿个用户 id, 每个小时算法工程师会根据每个用户之前历史行为计算出推荐数据放到存储层中, 但是最新的用户由于没有历史行为, 就会发生缓存穿透的行为, 为此可以将所有推荐数据的用户做成布隆过滤器。 如果布隆过滤器认为该用户 id 不存在, 那么就不会访问存储层, 在一定程度保护了存储层。此时的结构如下图:
  • 布隆过滤器
  • 当然布隆过滤器的假阳性的存在导致了误判率,但是我们可以尽量的降低误判率,一个解决方案就是:使用多个 Hash 算法为元素计算出多个 Hash 值,只有所有 Hash 值对应的数组中的值都为 1 时,才会认为这个元素在集合中。
  • 这种方法适用于数据命中不高数据相对固定实时性低(通常是数据 集较大)的应用场景,代码维护较为复杂,但是缓存空间占用少。为什么呢?因为布隆过滤器不支持删除元素,一旦数据变化,并不能及时的更新布隆过滤器。

两种方案对比

  • 两种方案各有优缺点,具体使用哪种方案还是要根据业务场景和系统体量来定。具体的区别如下表:
方案 适用场景 维护成本
缓存对象 1. 数据命中不高 2. 数据频繁变化,实时性高 代码维护点单、需要过多的缓存空间,数据一致性需要自己实现
布隆过滤器 1. 数据命中不高 2.数据相对固定,实时性低 代码维护复杂、缓存空间占用少

总结

  • 至此,如何解决缓存穿透的问题已经介绍完了,觉得写得不错的,有所收获的朋友,点点在看,分享关注一波。
  • 最近不少读者留言陈某希望我多发一些面试题,这几天正好在整理大厂面试常问的面试题,后面会陆续发布,已经发布的面试题有两篇,分别是【吊打面试官】Mysql 大
  • 厂高频面试题!!!Redis 高频面试题及答案。关注陈某,每天都会有面试题更新!!!
  • 看完这篇缓存穿透的文章,又能和面试官互扯了~[亲测有效]

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/8776.html

(0)
上一篇 2023-02-22
下一篇 2023-02-22

相关推荐

  • Redis阻塞_redis订阅发布堵塞问题

    Redis阻塞_redis订阅发布堵塞问题可能存在问题 内在原因:API或数据结构使用不合理、CPU饱和、持久化阻塞等 外在原因:CPU竞争、内存交换、网络问题等 问题处理: API或数据结构使用不合理,可能存在慢查询或者大对象: 发现慢查…

    2023-04-01
    164
  • Centos安装Cloudera Manager 6.3.0和CDH 6.3.2

    Centos安装Cloudera Manager 6.3.0和CDH 6.3.2前言 闲暇之时,羚羊给大家分享一下羚羊在Centos7 下安装Cloudera Manager 6.3.0和cloudera cdh 6.3.2的过程和安装过程中遇到的坑。至于为什么要选择C

    2023-03-17
    146
  • mysql相关知识整理(参考《高性能MySQL》)

    mysql相关知识整理(参考《高性能MySQL》)1.事务的特性 1.原子性:一个事务必须被视为一个不可分割的最小工作单元;事务的操作,要么全部成功,要么全部失败。 2.一致性:数据库总是从一个一致性的状态转换到另一个一致性的状态。 3.隔离性:通…

    2023-03-04
    134
  • 列存储索引_索引存储和散列存储

    列存储索引_索引存储和散列存储作者:李红建 责编:宇亭 在第一期研发分享中,我们解释了,为什么Tinamu作为一款列式存储引擎在初期不支持 Delete 功能的原因,然后对一些友商列式存储引擎的 Delete 方案进行了一些调研和

    2023-06-19
    155
  • python猜数字游戏脚本(python怎么做猜数字游戏)

    python猜数字游戏脚本(python怎么做猜数字游戏)核心代码给你,具体的功能还需要自己完善。

    2023-10-28
    130
  • 故障分析 | MySQL 优化案例 – 字符集转换「建议收藏」

    故障分析 | MySQL 优化案例 – 字符集转换「建议收藏」作者:xuty 本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。 本文关键字:SQL 优化、字符集 一、背景 Server version: 5.7…

    2023-03-17
    162
  • Python Future概述

    Python Future概述Python语言自问世以来,一直得到了广泛的应用和支持,其在多种领域和行业中都有着重要的地位。而这个支持和应用的趋势还在不断加强,我们能够看到许多的技术、工具、框架、语法等等,都在不断的壮大和完善。在这篇文章中,我们将探讨Python的未来发展趋势,了解在众多的技术中,Python将如何持续的发展和壮大。

    2024-05-22
    58
  • Redis基本操作进阶篇-[亲测有效]

    Redis基本操作进阶篇-[亲测有效]Redis中的事务(transaction)是一组命令的集合。一个事务中的命令要么全部执行,要么都不执行。Redis的事务没有关系数据库事务提供的回滚(rollback)功能。

    2023-05-03
    154

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注