Redis总结(三)

目录

什么是缓存预热、缓存雪崩、缓存击穿、缓存穿透?

缓存预热

缓存雪崩

解决方案

针对Redis故障宕机

针对大量key同时过期

缓存击穿

解决方案

缓存穿透

解决方案

总结

数据库和缓存如何保证一致性?

先更新缓存还是先更新数据库?

异常情况下引发的数据一致性问题

1.先更新数据库,再更新缓存

2.先更新缓存,再更新数据库

并发情况下引发的一致性问题

1.先更新数据库,再更新缓存

解决方案

2.先更新缓存,再更新数据库

先删除缓存再更新数据库还是先更新数据库再删除缓存?

并发情况下引发的一致性问题

1.先删除缓存,再更新数据库

解决方案

2.先更新数据库,再删除缓存

 如何保证两步都成功?

1.重试机制

2.订阅数据库变更日志:

总结


什么是缓存预热、缓存雪崩、缓存击穿、缓存穿透?

缓存预热

缓存预热就是系统上线后,提前将相关的缓存数据直接加载到缓存系统。避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!

缓存雪崩

大量key同时过期或Redis故障宕机时,如果有大量的用户请求,都无法再Redis中处理,于是全部请求都直接访问数据库,从而导致数据库压力骤增,严重会导致数据库宕机,从而形成一系列连锁反应,造成整个数据库崩溃,这就是缓存雪崩。

解决方案

针对Redis故障宕机

1.采用Redis集群,避免单机出现问题导致整个缓存服务都没法使用

2.服务熔断或请求限流机制:因为Redis宕机而导致的缓存雪崩问题时,可以启动服务熔断机制,暂停业务应用对缓存服务的访问,直接返回错误,不再继续访问数据库,从而降低对数据库的压力,保证数据库系统的正常运行,然后等到 Redis 恢复正常后,再允许业务应用访问缓存服务。

服务熔断机制是保护数据库的正常允许,但是暂停了业务应用访问缓存服系统,全部业务都无法正常工作,为了减少对业务的影响,我们可以启用请求限流机制,只是将少部分请求发送到数据库进行处理,再多的请求就在入口处直接拒绝服务,等到Redis恢复正常并把缓存预热完后,在解除请求的限流机制。

针对大量key同时过期

1.均匀key过期时间,应避免大量key同一时间过期。

2.互斥锁:在线程处理业务请求时,如果发现访问的数据不在Redis数据库中,就加个互斥锁,保证同一时间只有一个请求从数据库中读取数据,再将缓存更新到Redis中。(设置互斥锁时,最好设置超时时间,避免当请求拿到锁后,这个请求发生某种情况一直阻塞,无法释放锁,导致其他请求也拿不到锁,系统发生无响应现象)。

3.后台更新缓存:业务线程不再负责更新缓存,缓存也不设置有效期,而是让缓存“永久有效”,并让更新缓存的工作交由后台线程定时更新。

缓存击穿

如果缓存中的某个热点数据过期了,此时大量请求访问了该热点数据,就无法从缓存中读取,直接访问数据库,数据库就很容易被高并发的请求冲垮,这就是缓存击穿。

解决方案

1.互斥锁方案,保证同一时间只有一个业务线程在更新缓存,未获取互斥锁的请求,要么等待锁释放后重新读取缓存,要么就返回空值或者默认值。

2.不给热点数据设置过期时间,由后台异步更新缓存,或者在热点数据准备要过期前,提前通知后台线程更新缓存以及重新设置过期时间;

3.差异失效时间:新建两块缓存,主A从B,先更新B在更新A,严格按照这个顺序。当查询缓存时,先查询主缓存A,如果A中没有所需数据,在查询从缓存B。

缓存穿透

当用户访问数据时,数据既不在缓存中,也不在数据库中,导致请求在访问缓存时,发现缓存缺失,再去访问数据库时,发现数据库中也没有要访问的数据,没法构建缓存数据,来服务后续的请求。那么当有大量这样的请求到来时,数据库压力骤增,这就是缓存穿透。

缓存穿透的发生一般有两种情况:

1.业务操作失误,缓存中的数据和数据库中的数据都被删除了,所以导致缓存和数据库中都没有数据;

2.黑客恶意攻击。故意大量访问不存在的数据的业务。

解决方案

1.非法请求的限制:当有大量恶意请求访问不存在的数据的时候,也会发生缓存穿透,因此在 API 入口处我们要判断求请求参数是否合理,请求参数是否含有非法值、请求字段是否存在,如果判断出是恶意请求就直接返回错误,避免进一步访问缓存和数据库。

2.设置空值或默认值:当我们线上业务发现缓存穿透的现象时,可以针对查询的数据,在缓存中设置一个空值或者默认值,这样后续请求就可以从缓存中读取到空值或者默认值,返回给应用,而不会继续查询数据库。

3.使用布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在:我们可以在写入数据库数据时,使用布隆过滤器做个标记,然后在用户请求到来时,业务线程确认缓存失效后,可以通过查询布隆过滤器快速判断数据是否存在,如果不存在,就不用通过查询数据库来判断数据是否存在,即使发生了缓存穿透,大量请求只会查询 Redis 和布隆过滤器,而不会查询数据库,保证了数据库能正常运行,Redis 自身也是支持布隆过滤器的。

需要注意的是布隆过滤器可能会存在误判的情况。总结来说就是:布隆过滤器说某个元素存在,小概率会误判。布隆过滤器说某个元素不在,那么这个元素一定不在。

总结

数据库和缓存如何保证一致性?

先更新缓存还是先更新数据库?

先不考虑并发问题,正常情况下,无论谁先谁后,都会更新成功,但异常情况下可能会发生【第一步操作成功、第二步操作失败的情况】

异常情况下引发的数据一致性问题

1.先更新数据库,再更新缓存

更新数据库成功,更新缓存失败,那么此时数据库中是最新值,缓存中是旧值,之后读到的就是旧值,只有当缓存失效后,才能从数据库中得到正确得值。

2.先更新缓存,再更新数据库

更新缓存成功,更新数据库失败,那么此时缓存中是最新值,数据库中是旧值,之后读到的是缓存中的新值,但当缓存失效后,从数据库中又会读到旧值。

并发情况下引发的一致性问题

1.先更新数据库,再更新缓存

假如有两个请求,请求A和请求B,同时更新同一条数据可能会出现这样的情况:

请求A先将数据库中数据更新为1,然后在更新缓存前,请求B将数据库数据更新为2,紧接着也把缓存更新为2,然后 请求A将缓存更新为1,此时数据库中数据为1,缓存中数据为2,出现了缓存和数据库中数据不一致情况。

解决方案

1.采用分布式锁:在更新缓存前先加个分布式锁,保证同一时间只运行一个请求更新缓存,就会不会产生并发问题了,当然引入了锁后,对于写入的性能就会带来影响。

2.设置过期时间:在更新完缓存时,给缓存加上较短的过期时间,这样即时出现缓存不一致的情况,缓存的数据也会很快过期,对业务还是能接受的。

2.先更新缓存,再更新数据库

假如有两个请求,请求A和请求B,同时更新同一条数据可能会出现这样的情况:

A 请求先将缓存的数据更新为 1,然后在更新数据库前,B 请求来了, 将缓存的数据更新为 2,紧接着把数据库更新为 2,然后 A 请求将数据库的数据更新为 1。

此时,数据库中的数据是 1,而缓存中的数据却是 2,出现了缓存和数据库中的数据不一致的现象。

先删除缓存再更新数据库还是先更新数据库再删除缓存?

所以,无论是「先更新数据库,再更新缓存」,还是「先更新缓存,再更新数据库」,这两个方案都存在并发问题,当两个请求并发更新同一条数据的时候,可能会出现缓存和数据库中的数据不一致的现象

此时需要考虑另一种方案:删除缓存。在更新数据时,不更新缓存,而是删除缓存中的数据。然后,到读取数据时,发现缓存中没了数据之后,再从数据库中读取数据,更新到缓存中。即Cache Aside(旁路缓存)策略。

对于异常情况,但凡第二步操作失败,肯应会引起数据不一致,这里重点介绍并发问题带来的数据不一致情况。

并发情况下引发的一致性问题

1.先删除缓存,再更新数据库

有两个请求,请求A进行写操作,请求B进行读操作

1)请求A进行写操作,删除redis缓存后,工作正在进行中,更新mysql......A还么有彻底更新完mysql,还没commit

(2)请求B开工查询,查询redis发现缓存不存在(被A从redis中删除了)

(3)请求B继续,去数据库查询得到了mysql中的旧值(A还没有更新完)

(4)请求B将旧值写回redis缓存

(5)请求A将新值写入mysql数据库

上述情况会出现数据不一致情况

解决方案

1.延迟双删:在线程 A 删除缓存、更新完数据库之后,先「休眠一会」,再「删除」一次缓存。

#删除缓存
redis.delKey(X)
#更新数据库
db.update(X)
#睡眠
Thread.sleep(N)
#再删除缓存
redis.delKey(X)

加了个睡眠时间,主要是为了确保请求 A 在睡眠的时候,请求 B 能够在这这一段时间完成「从数据库读取数据,再把缺失的缓存写入缓存」的操作,然后请求 A 睡眠完,再删除缓存。

所以,请求 A 的睡眠时间就需要大于请求 B 「从数据库读取数据 + 写入缓存」的时间。

2.先更新数据库,再删除缓存

继续用「读 + 写」请求的并发的场景来分析。

假如某个用户数据在缓存中不存在,请求 A 读取数据时从数据库中查询到年龄为 20,在未写入缓存中时另一个请求 B 更新数据。它更新数据库中的年龄为 21,并且清空缓存。这时请求 A 把从数据库中读到的年龄为 20 的数据写入到缓存中。

最终,该用户年龄在缓存中是 20(旧值),在数据库中是 21(新值),缓存和数据库数据不一致。

从上面的理论上分析,先更新数据库,再删除缓存也是会出现数据不一致性的问题,但是在实际中,这个问题出现的概率并不高

因为缓存的写入通常要远远快于数据库的写入,所以在实际中很难出现请求 B 已经更新了数据库并且删除了缓存,请求 A 才更新完缓存的情况。

而一旦请求 A 早于请求 B 删除缓存之前更新了缓存,那么接下来的请求就会因为缓存不命中而从数据库中重新读取数据,所以不会出现这种不一致的情况。

 如何保证两步都成功?

前面我们分析到,无论是更新缓存还是删除缓存,只要第二步发生失败,那么就会导致数据库和缓存不一致。

1.重试机制

可以引入消息队列,将第二个操作(删除缓存)要操作的数据加入到消息队列,由消费者来操作数据。

  • 如果应用删除缓存失败,可以从消息队列中重新读取数据,然后再次删除缓存,这个就是重试机制。当然,如果重试超过的一定次数,还是没有成功,我们就需要向业务层发送报错信息了。
  • 如果删除缓存成功,就要把数据从消息队列中移除,避免重复操作,否则就继续重试。

2.订阅数据库变更日志:

先更新数据库,再删缓存」的策略的第一步是更新数据库,那么更新数据库成功,就会产生一条变更日志,记录在 binlog 里。

于是我们就可以通过订阅 binlog 日志,拿到具体要操作的数据,然后再执行缓存删除。

总结

文章参考:

2.小林coding:图解Redis介绍 | 小林coding

3. 尚硅谷Redis7实战:尚硅谷Redis零基础到进阶,最强redis7教程,阳哥亲自带练(附redis面试题)_哔哩哔哩_bilibili

4.javaguide:Java 面试指南 | JavaGuide(Java面试 + 学习指南)

5.水滴与银弹公众号:缓存和数据库一致性问题,看这篇就够了 (qq.com)

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

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

相关文章

【sgLazyCascader】自定义组件:基于el-cascader的懒加载级联菜单,支持异步加载子级菜单

sgLazyCascader源码 <template><div :class"$options.name"><el-cascader :props"props" v-model"model" :placeholder"placeholder || 请选择" :options"options"></el-cascader></div> &l…

【Docker】镜像的创建、管理与发布

镜像的获取 镜像可以从以下方式获得&#xff1a; 从远程镜像仓库拉取&#xff0c;可以是公有仓库&#xff0c;也可以是私有仓库从Dockerfile构建从文件导入&#xff08;离线&#xff09;从容器提交 镜像的基本操作 跟镜像相关的命令如下&#xff1a; $ docker image --help…

Android 11.0 ota升级之Systemui下拉状态栏quick_settings_tiles_default值减少时更新的功能实现

1.前言 在11.0的系统rom定制化开发中,在定制功能需求中,在进行systemui的下拉状态栏定制以后,当需要ota升级的时候,发现在systemui下拉状态栏的快捷功能键部分去掉的 一些快捷功能并没有减少,这是因为systemui有缓存造成的只有清理缓存或者恢复出厂设置后才正常,所以今天…

【算法题】2651. 计算列车到站时间

题目&#xff1a; 给你一个正整数 arrivalTime 表示列车正点到站的时间&#xff08;单位&#xff1a;小时&#xff09;&#xff0c;另给你一个正整数 delayedTime 表示列车延误的小时数。 返回列车实际到站的时间。 注意&#xff0c;该问题中的时间采用 24 小时制。 示例 1…

大数据-玩转数据-Flink状态编程(上)

一、Flink状态编程 有状态的计算是流处理框架要实现的重要功能&#xff0c;因为稍复杂的流处理场景都需要记录状态&#xff0c;然后在新流入数据的基础上不断更新状态。 SparkStreaming在状态管理这块做的不好, 很多时候需要借助于外部存储(例如Redis)来手动管理状态, 增加了编…

macbookpro怎么删除软件没有鼠标

macbookpro怎么删除软件没有鼠标,macbookpro触摸板可以替代鼠标进行操作。左右键功能与鼠标相同&#xff0c;可用于执行删除操作。此外&#xff0c;还可以利用键盘上的Delete键来删除选中的文件。 删除软件方法 方法1、打开应用程序&#xff0c;键盘按住control&#xff0c;加点…

数据结构与算法之贪心动态规划

一&#xff1a;思考 1.某天早上公司领导找你解决一个问题&#xff0c;明天公司有N个同等级的会议需要使用同一个会议室&#xff0c;现在给你这个N个会议的开始和结束 时间&#xff0c;你怎么样安排才能使会议室最大利用&#xff1f;即安排最多场次的会议&#xff1f;电影的话 那…

高等数学教材重难点题型总结(四)不定积分

难点在于量级&#xff0c;不定积分一定要多练多见才能游刃有余~ 1.利用求导公式验证等式 2.计算不定积分

C语言——指针完全版

目录 一、指针的运算 1.1指针 - 整数 1.2指针 - 指针 二、指针遍历数组 2.1指针遍历数组 1.了解数组名称的含义&#xff08;&数组名和数组名的区别&#xff09;。 2.用指针遍历数组 三、指针数组、数组指针、函数指针 3.1指针数组 3.1.1指针数组的形式 3.1.2指针…

【自学笔记】如何在 Python 中使用 YAML 文件? 了解 YAML 格式和规范

文章目录 如何在 Python 中使用 YAML 文件YAML 的格式、规范和需要注意的点YAML 的缩进对象块其语法规范在 Python 中使用 PyYAML 模块安装 PyYAML 模块使用 PyYAML 模块读取和写入 YAML 文件读取 YAML 文件写入 YAML 文件load() 和 safe_load() 的区别总结如何在 Python 中使用…

day33 List接口

List实现类 java.util.ArrayList&#xff1a; 底层通过数组保存数据 &#xff0c; 查询快&#xff0c;增删慢 java.util.LinkedList&#xff1a; 底层通过链表保存数据&#xff0c; 查询慢&#xff0c;增删快 如果对操作性能没有特殊要求&#xff0c;我们一般选择ArrayList…

【力扣每日一题】2023.9.7 修车的最少时间

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们一个数值&#xff0c;数组里每个元素表示一个老师傅&#xff0c;老师傅修车花费的时间等于数值乘上车辆数的平方。 问我们修理…

vue中使用tailwindcss

Tailwind CSS with Vue tailwindcss官方文档 创建Vue项目 npm create vitelatest my-project -- --template vue cd my-project安装Tailwind CSS&#xff0c;创建tailwind.config.js和postcss.config.js npm install -D tailwindcss postcss autoprefixer npx tailwindcss …

编程语言排行榜

以下是2023年的编程语言排行榜&#xff08;按照流行度排序&#xff09;&#xff1a; Python&#xff1a;Python一直以来都是非常受欢迎的编程语言&#xff0c;它简洁、易读且功能强大。在数据科学、机器学习、人工智能等领域有广泛应用。 JavaScript&#xff1a;作为前端开发…

你不知道的JavaScript---对象

1.语法 对象可以通过两种方式定义&#xff1a;一种是对象字面量形式&#xff0c;一种是构造形式 对象字面量&#xff1a; var muObject {key: value }构造形式的&#xff1a; var myObject new Object() myObject.key value不管是使用对象字面量形式还是构造形式创建出来…

idea:java: Compilation failed: internal java compiler error

java: Compilation failed: internal java compiler error错误 检查下面2个即可&#xff1a;

docker 生成镜像的几个问题

docker 生成镜像的几个问题 根据jdk8.tar.gz 打包Jdk8 镜像失败运行镜像报错差不多是网络ip错误,在网上说重启docker即可解决运行mysql5.7.25 镜像失败向daemon.json文件添加内容导致docker重启失败docker run 命令常用参数根据jdk8.tar.gz 打包Jdk8 镜像失败 首选做准备工作…

卡牌类游戏推荐,卡牌类三国手游排行榜

以下是小编要推荐给大家的关于卡牌类三国手游排行榜的内容。这里有来自各个历史阶段的名将和美女&#xff0c;让你体验最真实的三国战役。你可以将各种战略思维运用到其中&#xff0c;感受步步为营的喜悦&#xff0c;最终赢得战火纷飞的三国&#xff0c;如果想了解每个游戏的具…

浅谈安科瑞ADL200仪表在爱尔兰工厂的应用

摘要&#xff1a;用户端消耗着整个电网80%的电能&#xff0c;用户端智能化用电管理对用户可靠、安全、节约用电有十分重要的意义。构建智能用电服务体系&#xff0c;推广用户端智能多功能仪表、智能用电管理终端等设备用电管理解决方案&#xff0c;实现电网与用户的双向良性互动…

失效的访问控制及漏洞复现

文章目录 渗透测试漏洞原理失效的访问控制1. 失效的访问控制1.1 OWASP TOP 101.1.1 A5:2017-Broken Access Control1.1.2 A01:2021-Broken Access Control 1.2 失效的访问控制类别1.2.1 水平越权1.2.2 垂直越权 1.3 攻防案例1.3.1 DVWA越权 1.4 相关漏洞1.4.1 目录遍历1.4.2 未…