缓存穿透、缓存雪崩、缓存击穿?

背景

在现代软件架构中,缓存的应用已经非常普及。缓存的使用在面试和实践中都是避不开的硬技能、硬知识,如果你说还不太熟悉缓存的使用,可能都不好意思说自己是程序员。

这篇文章,带大家进一步学习在缓存使用中不得不考虑三个特殊场景:缓存穿透、缓存雪崩、缓存击穿。

为什么说不得不考虑?因为如果不考虑这些特殊的场景,在高并发的情况可能直接导致系统崩溃。下面以常见的Redis缓存组件为例来讲解这三种场景及解决方案。

大前提

当我们使用缓存时,目标通常有两个:第一,提升响应效率和并发量;第二,减轻数据库的压力。

而本文中所提到的这三种场景:缓存穿透、缓存雪崩和缓存击穿的发生,都是因为在某些特殊情况下,缓存失去了预期的功能所致。

当缓存失效或没有抵挡住流量,流量直接涌入到数据库,在高并发的情况下,可能直接击垮数据库,导致整个系统崩溃。

这就是我们需要知道的大前提,而缓存穿透、缓存雪崩和缓存击穿,只不过是在这个大前提下的不同场景的细分场景而已。

缓存穿透

大多数情况,缓存可以减少数据库的查询,提升系统性能。

通常流程是:一个请求过来,先查询是否在缓存当中,如果缓存中存在,则直接返回。如果缓存中不存在对应的数据,则检索数据库,如果数据库中存在对应的数据,则更新缓存并返回结果。如果数据库中也不存在对应的数据,则返回空或错误。

缓存穿透(cache penetration)是用户访问的数据既不在缓存当中,也不在数据库中。出于容错的考虑,如果从底层数据库查询不到数据,则不写入缓存。这就导致每次请求都会到底层数据库进行查询,缓存也失去了意义。当高并发或有人利用不存在的Key频繁攻击时,数据库的压力骤增,甚至崩溃,这就是缓存穿透问题。

549877544eb3bb87ce8ab480055a297f.jpeg
缓存穿透

缓存穿透发生的场景一般有两类:

  • 原来数据是存在的,但由于某些原因(误删除、主动清理等)在缓存和数据库层面被删除了,但前端或前置的应用程序依旧保有这些数据;

  • 恶意攻击行为,利用不存在的Key或者恶意尝试导致产生大量不存在的业务数据请求。

缓存穿透通常有四种解决方案,我们逐一介绍分析。

方案一:缓存空值(null)或默认值

分析业务请求,如果是正常业务请求时发生缓存穿透现象,可针对相应的业务数据,在数据库查询不存在时,将其缓存为空值(null)或默认值。需要注意的是,针对空值的缓存失效时间不宜过长,一般设置为5分钟之内。当数据库被写入或更新该key的新数据时,缓存必须同时被刷新,避免数据不一致。

方案二:业务逻辑前置校验

在业务请求的入口处进行数据合法性校验,检查请求参数是否合理、是否包含非法值、是否恶意请求等,提前有效阻断非法请求。比如,根据年龄查询时,请求的年龄为-10岁,这显然是不合法的请求参数,直接在参数校验时进行判断返回。

方案三:使用布隆过滤器请求白名单

在写入数据时,使用布隆过滤器进行标记(相当于设置白名单),业务请求发现缓存中无对应数据时,可先通过查询布隆过滤器判断数据是否在白名单内,如果不在白名单内,则直接返回空或失败。

方案四:用户黑名单限制

当发生异常情况时,实时监控访问的对象和数据,分析用户行为,针对故意请求、爬虫或攻击者,进行特定用户的限制;

当然,可能针对缓存穿透的情况,也有可能是其他的原因引起,可以针对具体情况,采用对应的措施。

缓存雪崩

在使用缓存时,通常会对缓存设置过期时间,一方面目的是保持缓存与数据库数据的一致性,另一方面是减少冷缓存占用过多的内存空间。

但当缓存中大量热点缓存采用了相同的实效时间,就会导致缓存在某一个时刻同时实效,请求全部转发到数据库,从而导致数据库压力骤增,甚至宕机。从而形成一系列的连锁反应,造成系统崩溃等情况,这就是缓存雪崩(Cache Avalanche)。

80af4b84a36090b9ee84de40c04a1a09.jpeg
缓存雪崩

上面讲到的是热点key同时失效的场景,另外就是由于某些原因导致缓存服务宕机、挂掉或不响应,也同样会导致流量直接转移到数据库。

所以,缓存雪崩的场景通常有两个:

  • 大量热点key同时过期;

  • 缓存服务故障;

缓存雪崩的解决方案:

  • 通常的解决方案是将key的过期时间后面加上一个随机数(比如随机1-5分钟),让key均匀的失效。

  • 考虑用队列或者锁的方式,保证缓存单线程写,但这种方案可能会影响并发量。

  • 热点数据可以考虑不失效,后台异步更新缓存,适用于不严格要求缓存一致性的场景。

  • 双key策略,主key设置过期时间,备key不设置过期时间,当主key失效时,直接返回备key值。

  • 构建缓存高可用集群(针对缓存服务故障情况)。

  • 当缓存雪崩发生时,服务熔断、限流、降级等措施保障。

缓存击穿

缓存雪崩是指只大量热点key同时失效的情况,如果是单个热点key,在不停的扛着大并发,在这个key失效的瞬间,持续的大并发请求就会击破缓存,直接请求到数据库,好像蛮力击穿一样。这种情况就是缓存击穿(Cache Breakdown)。

91ba983dee67753bc412d500948c3b7d.jpeg
缓存击穿

从定义上可以看出,缓存击穿和缓存雪崩很类似,只不过是缓存击穿是一个热点key失效,而缓存雪崩是大量热点key失效。因此,可以将缓存击穿看作是缓存雪崩的一个子集。

缓存击穿的解决方案:

  • 使用互斥锁(Mutex Key),只让一个线程构建缓存,其他线程等待构建缓存执行完毕,重新从缓存中获取数据。单机通过synchronized或lock来处理,分布式环境采用分布式锁。

  • 热点数据不设置过期时间,后台异步更新缓存,适用于不严格要求缓存一致性的场景。

  • ”提前“使用互斥锁(Mutex Key):在value内部设置一个比缓存(Redis)过期时间短的过期时间标识,当异步线程发现该值快过期时,马上延长内置的这个时间,并重新从数据库加载数据,设置到缓存中去。

小结

本文介绍了在使用缓存时经常会遇到的三种异常情况:缓存穿透、缓存雪崩和缓存击穿。

三种异常情况从根本上来说都是因为本应该访问缓存的,但是缓存不存在或服务异常,导致流量直接进入了数据库层面。

其中缓存雪崩和缓存击穿是因为数据不存在(或服务异常获取不到),导致大量请求访问数据库,从而导致数据库压力骤增,甚至崩溃。

而缓存穿透则是由于数据本身就不存在,导致缓存没有进行数据缓存,流量进入数据库层。

针对不同的缓存异常场景,可选择不同的方案来进行处理。当然,除了上述方案,我们还可以限流、降级、熔断等服务层的措施,也可以考虑数据库层是否可以进行横向扩展,当缓存异常发生时,确保数据库能够抗住流量,不至于让整个系统崩溃。

9ff869b8c9bb973a248bdff5d16e7fce.gif

往期推荐

09c3cebb7508423bfe0b6e1901de32ed.jpeg

面试突击65:HTTPS有什么优点?说一下它的执行流程?


96784d2688fa1c2ee24f3a9a00158d26.jpeg

面试拆解:系统上线后CPU急速飙升,该怎么排查?


631fdaba08f48a04347b38a7c7ea14a7.jpeg

面试突击63:distinct 和 group by有什么区别?


8b4907638a84e6f6b61321faf205c5a9.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/544060.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c语言 div ldiv_C ++中带有示例的ldiv()函数

c语言 div ldivC ldiv()函数 (C ldiv() function) ldiv() function is a library function of cstdlib header. It is used for integral division, it accepts two parameters (numerator and denominator) and returns a structure that contains the quot (quotient) and r…

网盘搜索

http://pan.java1234.com1、在http://baidu.com的搜索框中输入:site:http://pan.baidu.com 搜索词(回复中林涛同学建议第一条如果用谷歌搜site:百度网盘的话效果会好一点)2、壹搜 网盘搜索引擎3、盘易搜 盘易搜-百度网盘搜索4、BD盘搜索 百度…

如何防止订单重复支付?

大家好,我是磊哥,想必大家对在线支付都不陌生,今天和大家聊聊如何防止订单重复支付。看看订单支付流程我们来看看,电商订单支付的简要流程:订单钱包支付流程从下单/计算开始:下单/结算:这一步虽…

c ++atoi函数_atoi()函数以及C ++中的示例

c atoi函数C atoi()函数 (C atoi() function) atoi() function is a library function of cstdlib header. It is used to convert the given string value to the integer value. It accepts a string containing an integer (integral) number and returns its integer valu…

IOS沙盒中的Documents、Library、tmp区别

1.Documents: 用户生成的文件、其他数据及其他程序不能重新创建的文件,iTunes备份和恢复的时候会包括此目录。 2.Library/Caches: 可以重新下载或者重新生成的数据,数据库缓存文件和可下载内容应该保存到这个文件夹,iTunes不会备份此目录&…

3 分钟快速上手 Spring 事件机制

小伙伴们好呀~ 今天来和大家分享下这个 Spring事件机制内容概览image-20210829132019387原理image-20210828184103069这个熟悉 观察者模式 的小伙伴应该一眼就看出来啦~其实就是个简单版的 发布-订阅模式有三个核心类👇事件 ApplicationEvent事件发布器 Application…

mis dss gis_MIS中的决策支持系统(DSS)

mis dss gisThe Decision Support System is always helpful to management people to take decisions/decisions and finds the key business insights from available information systems. 决策支持系统始终有助于管理人员做出决策/决策,并从可用的信息系统中找到…

使用Grunt构建自动化开发环境

1、准备工作 1)首页确保电脑上网,以及能够访问https://registry.npmjs.org/,因需从此网站中下载安装相应的插件; 2)电脑安装Node.js,Grunt及Grunt插件都是基于node.js运行的;如果你电脑上未装node.js&#…

面试突击66:请求转发和请求重定向有什么区别?

作者 | 磊哥来源 | Java面试真题解析(ID:aimianshi666)转载请联系授权(微信ID:GG_Stone)在 Java 中,跳转的实现方式有两种:请求转发和请求重定向,但二者是完全不同的&…

python 示例_带有示例的Python列表copy()方法

python 示例列出copy()方法 (List copy() Method) copy() method is used to copy a list, the method is called with this list (current/original list) and returns a list of the same elements. copy()方法用于复制列表,该方法与此列表一起调用(当前/原始列表…

99%的Java程序员会踩的6个坑

前言作为Java程序员的你,不知道有没有踩过一些基础知识的坑。有时候,某个bug,你查了半天,最后发现竟然是一个非常低级的错误。有时候,某些代码,这一批数据功能正常,但换了一批数据就出现异常了。…

输出一个数的二进制序列中1的个数(三种方法)

由于这个数有可能是负数&#xff0c;负数在计算机中以补码的方式存储&#xff0c;要求负数的补码中1的个数依然可以正确输出&#xff0c;方法如下&#xff1a;1、定义这个数的变量类型为无符号整型&#xff08;unsigned int&#xff09;代码为include<stdio.h>int count_…

BigDecimal 的 4 个坑,你踩过几个?

背景 一直从事金融相关项目&#xff0c;所以对BigDecimal再熟悉不过了&#xff0c;也曾看到很多同学因为不知道、不了解或使用不当导致资损事件发生。所以&#xff0c;如果你从事金融相关项目&#xff0c;或者你的项目中涉及到金额的计算&#xff0c;那么你一定要花时间看看这篇…

Windows Server 2012 R2 里面如何安装Net Framework 3.5

图示 不要慌&#xff0c;和windows是不一样的&#xff0c;没有问题 下一步 默认即可&#xff0c;下一步 这里面的东西以后会装&#xff0c;先不管&#xff0c;我们今天目的是装 net framework 3.5 选一下 正在安装 如果出错了请参考&#xff1a; http://www.2cto.com/os/201410…

python计算连续复利_复利的Python程序

python计算连续复利Given principle amount, rate and time and we have to find the compound interest in Python. 给定原理量&#xff0c;速率和时间&#xff0c;我们必须找到Python的复利 。 计算复利 (Calculate compound interest) To calculate compound interest, we …

聊聊Java中代码优化的30个小技巧

今天我们一起聊聊Java中代码优化的30个小技巧&#xff0c;希望会对你有所帮助。1.用String.format拼接字符串不知道你有没有拼接过字符串&#xff0c;特别是那种有多个参数&#xff0c;字符串比较长的情况。比如现在有个需求&#xff1a;要用get请求调用第三方接口&#xff0c;…

scala 字符串函数_Scala中的字符串chomp(或chop)函数

scala 字符串函数剁或剁弦 (Chop or Chomp string) It is used to chop off the end of line characters. For this Scala has an inbuilt method stripLineEnd. 它用于截断行尾字符。 为此&#xff0c;Scala具有内置方法stripLineEnd 。 Syntax: 句法&#xff1a; string.st…

Linux扩展根分区大小

1、查看当前逻辑卷的分布df -h2、卸载home分区umount /home注意&#xff1a;无法卸载时候&#xff0c;使用以下命令结束进程&#xff1a;fuser -m /home3、调整home分区大小为20Gresize2fs -p /dev/mapper/VolGroup-lv_home 20G4、检查home分区e2fsck -f /dev/mapper/VolGroup-…

面试突击69:TCP 可靠吗?为什么?

作者 | 磊哥来源 | Java面试真题解析&#xff08;ID&#xff1a;aimianshi666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;相比于 UDP 来说&#xff0c;TCP 的主要特性是三个&#xff1a;有连接、可靠、面向数据流。所谓的“有连接”指的是 …

vc++中画线时xor_C ++'xor_eq'关键字和示例

vc中画线时xor"xor_eq" is an inbuilt keyword that has been around since at least C98. It is an alternative to ^ (EXCLUSIVE-OR Assignment) operator and it mostly uses for bit manipulations. “ xor_eq”是一个内置关键字&#xff0c;至少从C 98起就存在…