Redis缓存穿透、缓存雪崩、缓存击穿好好说说

前言

Redis是目前非常流行的缓存数据库啦,其中一个主要作用就是为了避免大量请求直接打到数据库,以此来缓解数据库服务器压力;用上缓存难道就高枕无忧了吗?no,no,no,没有这么完美的技术, 缓存穿透、缓存雪崩、缓存击穿这些问题都得好好聊聊。

正文

1. 缓存穿透

1.1 简要描述

缓存穿透是指查找的数据在缓存和数据库中都不存在,导致每一次请求数据从缓存中都获取不到,而将请求打到数据库服务器,但数据库中也没有对应的数据,最后每一次请求都到数据库;如果在高并发场景或有人恶意攻击,就会导致后台数据库服务器压力增大,最终系统可能崩掉。来个直接点的图:

简要说明:

缓存Redis服务器颜色说明:绿色块代表有缓存数据,粉色块代表缓存中没有数据;绿色箭头代表直接从缓存中获取数据;黄色箭头代表穿过缓存从数据库中查数据,但不一定有。

流程大概如下:

  1. 大量客户端发起大量请求到服务器;

  2. 服务器代码逻辑将先经过缓存,如果有缓存数据(绿色部分),直接从缓存中获取数据数据返回;如果缓存中没有数据(粉色部分),请求就会直接打到数据库服务器(如黄色箭头)。

  3. 如果存在大量无缓存数据的请求,最终数据库将因为过大压力而崩掉,导致系统不可用。

1.2 常用解决措施
  • 缓存空值:如果没有在数据库中获取到数据,可以将其对应键的空值进行缓存,并设置较短过期时间;

    优点:在过期时间内直接通过缓存返回空值;从而避免数据库压力;

    缺点:

    消耗Redis内存:如果是攻击者换着非常规的键值请求,如果每次都缓存到Redis中,大量的空数据也占内存空间;

    数据不一致:如果是正常数据,刚开始没有数据,然后将空值进行缓存,并设置短暂的过期时间;如果在过期时间内正常维护了对应的数据,此时取到值仍是空,并没有去数据库中获取新维护数据,导致数据获取不一致。

  • 布隆过滤器

    加一层过滤器进行拦截,判断请求对应的键是否在过滤器中,如果不在就直接返回,不去请求数据库,也不用缓存空值。而布隆过滤器采用bit位的形式标识对应键(每个键进行Hash过后都会得到具体的位置)是否存在,可以用极少的空间标识超大量的数据。

    缺点:布隆过滤器可以判断数据一定不在过滤器中,而对于存在的判断有误判率,因为Hash算法存在冲突的情况。

1.3 布隆过滤器

布隆过滤器不是专门用来针对缓存穿透的,它的应用场景很多,比如避免邮件重发、爬虫软件重爬、视频推送重复等;可能有的小伙伴还不明白为什么可以这么用,那先简单说说布隆过滤器的原理。

瞅个图先:

简要说明:

  1. 先来一个Key,后续需要判断Key是否存在(这里Key可以是任意想存的数据,比如用户ID、视频标识等);

  2. 将Key进行多次hash计算;每次的hash算法得到的结果都不一样;上图只画了三次hash计算,其实实际根据误判率不一样,hash次数就不一样;

  3. 将hash结果对应下标索引的bit位改为1,表示存在;上图经过三次hash,结果分别为2、5、9,则将对应的位置改为1;

  4. 如果需要判断Key是否在过滤器中,同样需进行多次hash计算,上图为三次,将计算出来的结果作为索引去获取对应的标识,三次中只要有一次对应位置的值为0,那就证明Key不存在过滤器中。如果是判定存在,则三次的结果对应位置的值应该都为1,不过这样是有误判可能,因为不同的Key,hash的结果有可能是一样的,从而就导致设置对应索引位时就会有冲突,如下图;


    先假设Key1、Key2经过三次hash的结果一样(实际场景是存在的),倘若Key1先来都将2、5、9位置的值设为1,那Key2进来判断存在时,由于hash的结果一样,从而就误判为在过滤器中,其实不存在;

    误判率在布隆过滤器中是可以控制,如果需要降低误判率,那就多进行几次hash计算,那位置相同的概率就降低啦;但这样会影响效率,另外也会有内存的额外开销,hash次数多,需要标识的位就越多。就算有误判率,也很小,在绝大多数场景下可接受。

1.4 布隆过滤器的使用

既然说Redis,就说Redis的布隆过滤器吧,其实小伙伴可以根据自己的需求利用Redis的bitmap实现。那有没有造好的轮子呢,当然有,在Redis4.0开始就有一个布隆过滤器的组件,开箱即用,当然也有一些其他大佬封装的,基于内存的,基于分布式都有。这里简单说说Redis布隆过滤器的插件,个人觉得挺好的,推荐哦。

官方文档地址:https://oss.redislabs.com/redisbloom/

我这面是用centos进行演示,主要步骤如下:

  1. 如果没有git的需要安装一下;如果不用git就去下载代码压缩包;

    yum install -y git
    
  2. 把redis布隆过滤器的源码搞下来,这里用git;也可以通过下载的方式;

    git clone https://github.com/RedisLabsModules/redisbloom.git
    
  3. 进入代码目录进行make(生成redisbloom.so文件),如果make命令找不到,就需要安装VC++编译相关的包;

    cd redisbloom
    make
    
  4. 在Redis配置文件中配置加载redisbloom插件,然后重启就可以用啦;也可以启动的时候指定加载插件运行;

    配置文件方式:在配置文件中添加如下配置,需要指定redisbloom.so具体的文件位置。


    然后指定配置文件启动即可;

    ./redis-server redis.conf
    启动时指定模块运行方式:
    
    ./redis-server --loadmodule ./redisbloom.so
  5. 简单使用


    命令使用和常规命令一样啦,就不需要我再写程序了吧,如果非要的话,那就简单说两句:

    A.将需要判断数据保存在过滤器中,比如所有的用户id;

    B.当请求过来时就先从过滤器中判断有无数据,没有直接返回,不去缓存,也不去数据库;

    C.如果有新添加的用户,需要将新的用户id放到过滤器中;

关于Redis布隆过滤器还有一些命令没说,小伙伴可以去逛逛官网。有小伙伴肯定会问,不用这个插件行吗,当然行啊,可以自己实现嘛,不过有些小伙伴有封装好的包啦,有基于内存的,也有基于Redis的,如下图:

代码我就不上了,剩下的就留给小伙伴啦。

2. 缓存雪崩

1.1 简要描述

缓存雪崩是指突然缓存层不可用,导致大量请求直接打到数据库,最终由于数据库压力过大可能导致系统崩掉。缓存层不可用指以下两方面:

  • 缓存服务器宕机,系统将请求打到数据库;

  • 缓存数据突然大范围集中过期失效,导致大量请求打到数据库重新加载数据;

如图:

简要说明:

缓存Redis服务器颜色说明:绿色块代表有缓存数据,粉色块代表缓存中没有数据;白色块代表大范围失效的缓存数据,绿色箭头代表直接从缓存中获取数据;黄色箭头代表穿过缓存从数据库中查数据。

流程大概如下:

  1. 大量客户端发起大量请求到服务器;

  2. 服务器代码逻辑将先经过缓存,如果有缓存数据(绿色部分),直接从缓存中获取数据数据返回;如果缓存过期(白色块部分),请求就会直接打到数据库服务器(如黄色箭头)

  3. 如果存在大量热数据的请求,但热数据又大范围过期,最终数据库将因为过大压力崩掉,导致系统不可用。

1.2 常用解决措施
  • 缓存预热:在高峰期还没到来时,提前将热数据加载到缓存中,避免高峰期来临时数据库压力过大。

  • 均匀设置过期时间:针对不同的热点数据,将过期时间加上一个随机值,让过期时间不集中在一个点,从而减小很大部分数据库压力;

  • 多级缓存:除了使用Redis缓存,还可以根据业务增加一些热点数据的其他缓存,比如内存缓存,可以将各级的缓存有效期分开,这种方式也能缓解数据库的压力;

  • 限流、降级:如果压力过大,避免把系统搞崩,可以增加一些限流手段,不管是中间件还是消息队列等,主要保证系统的可用。

  • 加互斥锁:目的就是加锁独占操作,让一个操作向缓存中重新加载数据,让请求操作等待,其实这样的体验不好,慎用。如果要用,要超级注意锁的性能和稳定性。

  • 对于缓存层整体崩掉的情况:使用高可用架构,比如之前说到的主从复制、哨兵、集群,根据需求进行对应架构,保证缓存层不崩掉。

3. 缓存击穿

1.1 简要描述

缓存击穿是指在超级热点数据突然过期,导致针对超级热点的数据请求在过期期间直接打到数据库,这样数据库服务器会因为某一超热数据导致压力过大而崩掉。

超热数据:比如秒杀时的数据,某宝、某东、某多多这种平台的数据如果在秒杀时间段失效,请求量足矣让数据库崩掉。

如图:

简要说明:

缓存Redis服务器颜色说明:绿色块代表有缓存数据,粉色块代表缓存中没有数据;白色圈代表超级热点缓存数据过期失效,绿色箭头代表直接从缓存中获取数据;黄色箭头代表穿过缓存从数据库中查数据。

流程大概如下:

  1. 大量客户端发起大量请求到服务器;

  2. 服务器代码逻辑将先经过缓存,如果有缓存数据(绿色部分),直接从缓存中获取数据数据返回;如果超热缓存数据过期(白色圈部分),请求就会直接打到数据库服务器(如黄色箭头)

  3. 超级热点数据过期失效,如秒杀数据,如果在秒杀时段失效,最终数据库将因为过大压力崩掉,导致系统不可用。

注:这个只是针对超热点数据,而不是大范围数据。

1.2 常用解决措施
  • 热点数据不过期:像这种超热数据就设置永不过期。避免过期失效让数据库压力过大而崩。

  • 加互斥锁:目的就是加锁,然后向缓存中重新加载数据,让请求等待,其实这样的体验不好,慎用。如果要用,要超级注意锁的性能和稳定性。

总结

缓存穿透、缓存雪崩、缓存击穿不管是哪个问题,其主要原因还是在缓存层没有命中,将请求直接打到数据库啦,最终导致数据库压力过大,系统不可用。小伙伴根据系统需要进行问题处理,没有完美的解决方案,但总会有一种适合需求的方案,解决业务问题才是真正目的。

今天没有上代码,相信小伙伴都能根据解决措施写出对应的代码,分布式锁可能稍微有点难搞,下次抽时间给大家安排上。

关于Redis系列,下篇说说Lua脚本就算初步完成啦,剩下的就是实战的总结啦,在项目的使用过程中,如果有好的方案和棘手的问题都会和小伙伴分享。接下来数据库优化系列即将开启,主要针对MySql。

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

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

相关文章

php字符串赋值给变量,JavaScript-如何将一个PHP字符串安全赋值给Javascript变量(包含引号和换行符的)...

php json_encode输出变量,在js使用(不是赋值)的时候转换成相应的字符串进行操作.注意:因为中文在json_encode会出问题。因此大家写了一个第三方的json_encode;class json {function __construct() {}function encode($array) {$this -> arrayRecursiv…

小计 合计 -统计

create table [tb]([客户编码] varchar(10),[客户名称] varchar(10),[数量] int) insert [tb] select 001,A,2 union all select 001,A,3 union all select 001,A,4 union all select 002,B,1 union all select 002,B,2 --统计 select * from (select * from tb union all s…

这是“我”的故事 —— 董彬

点击蓝字 关注我们作者:董彬校对/文章优化:刘轶民排版:Rani视频地址:https://www.bilibili.com/video/BV1NK4y1p7Ys与世界周旋的程序员大家好,我叫董彬 ,现就职于野村信息, Title 是 Senior …

我用Python玩小游戏“跳一跳”,瞬间称霸了朋友圈!

“从前几天微信最新版本 6.6.1 的更新开始,微信小程序游戏“跳一跳”似乎在一夜之间风靡了朋友圈。它甚至比五六年前的飞机大战游戏都火爆,这种小游戏的火爆不仅仅是因为有魔性、有意思,更重要的是可以进行好友 PK!“跳一跳”的小…

expsky.php,Typecho漏洞利用工具首发,半分钟完成渗透

原标题:Typecho漏洞利用工具首发,半分钟完成渗透*本文原创作者:expsky,本文属FreeBuf原创奖励计划,未经许可禁止转载声明:本工具由expsky原创,仅用于技术研究,不恰当使用会对网站造成…

游标 和 锁的概述

--用游标 declare str varchar(100) --定义游标 declare DZCursor CURSOR for SELECT test_str FROM test where test_strxxx --打开游标 open DZCursor --从游标取记录 fetch next from DZCursor into str --当有记录 while fetch_status0 begin insert into test (tes…

BeetleX之Web网关1.5.7安装使用

新版的网关主要升级到BeetleX最新版提高http协议的解释性能,从而让网关的吞吐能力进一步提升,在功能界面上也做了简单的调整让操作更方便,修复linux下无权限启动进程问题。如果在windows上不想用IIS,linux下用nginx怕麻烦&#xf…

JAVA world转图片,将Kinect深度图像转换为真实世界坐标

我正在使用kinect,使用OpenNI 2.x,c,OpenCV .我能够获得kinect深度流并获得灰度cv :: Mat . 只是为了说明它是如何定义的:cv::Mat m_depthImage;m_depthImage cvCreateImage(cvSize(640, 480), 8, 1);我想最接近的值用“0”表示&a…

费马大定理,集惊险与武侠于一体

悬案费马大定理从提出到证明的过程,就是一部不折不扣的惊险小说。一个读者,在自己看过的书空白处留下附注。除了他自己,还有谁会关注呢?但是,法国人费马死后,他在一本《算术》书上所写的注记并没有随之湮没…

全国计算机技术与软件专业技术资格(水平)考试基础知识

全国计算机技术与软件专业技术资格(水平)考试基础知识 -------------------------------------------------------------------------------- 1、什么是计算机技术与软件专业技术资格(水平)考试?  计算机技术与软件专…

python中pd series_python-比较pd.Series并在该系列不包含None时获得异常结果

我想知道为什么将两个相同的系列与None值进行比较会返回False:pd.Series([x, y, None]) pd.Series([x, y, None])0 True1 True2 Falsedtype: bool我希望所有结果都是正确的.如果我从系列中创建一个数组,并进行比较,我将得到预期的结果:pd.Series([x, y,…

GPU迎来投资热潮 退潮后谁在裸泳

近期,数家GPU设计公司获得资本青睐,摩尔线程完成数轮投资获得数十亿元,无独有偶,壁仞科技宣布完成总额11亿元的A轮融资,沐曦集成电路宣布完成近亿元天使轮融资,登临科技宣布完成A轮融资。另外,天…

网站底部运行时间的php代码,网站底部运行时间统计代码

也许您和我一样,想在自己站点底部或者任意位置添加一个运行时间统计的代码,对我来说这是一个特殊的日子,值得留恋,值得铭记。在这里我也收集并测试了部分,能有效的显示本站已运行N天,接下来上干货吧。js实现…

All in AI, 一句话看出了百度的野心,也看到了人工智能人才的未来

最近几天,在 2018 CES科技盛会上,百度无人驾驶系统 Apollo 2.0 正式开放,百度COO 陆奇表示,借着 Apollo 平台,他想打造中国无人车国家队!All in AI, 一句话看出了百度的野心。而百度,只是 China…

《Oracle大型数据库在AIX UNIX上的实战详解》的集中答疑九 数据库字符集与国家语言...

陆续收到若干同行来邮件,讨论关于数据库字符集和国家语言字符集之间的关系。这里我提出自己的看法。本文后面的内容部分来自网上关于Sybase ASE的一篇技术文摘,但下载日久,难分谁之作品,这里借用一下,如果正好是您的&a…

知名Node.js组件存在代码注入漏洞

喜欢就关注我们吧!日前,一个被大量下载的 Node.js 组件被发现其含有一个高危的代码注入漏洞。该漏洞被追踪为 CVE-2021-21315,影响了「systeminformation」npm 组件的安全性,该组件每周的下载量约为 80 万次,自诞生以来…

php判断子字符串位置,PHP怎样查询子字符串位置

字符串主要用于编程,字符串在存储上类似字符数组,所以它每一位的单个元素都是可以提取的。字符串或串(String)是由数字、字母、下划线组成的一串字符。一般记为 s“a1a2an”(n>0)。它是编程语言中表示文本的数据类型。在程序设计中,字符串…

icd11中文版精神障碍pdf_精神与行为障碍类别目录(ICD-11)

精神与行为障碍类别目录(ICD-11)神经发育障碍(7A00-7A43)7A00智力发育障碍,轻度7A01智力发育障碍,中度7A02智力发育障碍,重度7A03智力发育障碍,极重度7A04智力发育障碍,一过性7A0Z智力发育障碍,未特定7A10语…

VPC2007差分硬盘让小硬盘也能跑多个虚拟机

在Winos中看到http://bbs.winos.cn/thread-43391-1-1.html于 2008-9-2 16:02 发表基于Vmware Workstation 让你的小硬盘也能跑多个虚拟机个人认为有些做得不是很人性化。比如说我要把虚拟机母板封装好之后要修改为只读,而且还要隐藏起来。那么我再要创建虚拟机就要…

2017新生儿爆款名字出炉!90后的父母们最受欢迎的居然是.....

名字跟随一生因此很多家长在给孩子起名字的时候都相当谨慎除了日常迷信外不重名成为取名的重要考虑因素学校走廊里喊一声“子涵”,竟有3人回头!!你知道你家孩子的名字和多少人重名了吗?近日,江苏苏州一家科技公司发布《…