面试题:Redis(三)

1. 面试题

背景

 

问题,上面业务逻辑你用java代码如何写?

 

2. 缓存双写一致性谈谈你的理解?

 3. 双检加锁策略

多个线程同时去查询数据库的这条数据,那么我们可以在第一个查询数据的请求上使用一个 互斥锁来锁住它

其他的线程走到这一步拿不到锁就等着,等第一个线程查询到了数据,然后做缓存。

后面的线程进来发现已经有缓存了,就直接走缓存。 

4. 数据库和缓存一致性的几种更新策略

目的

给缓存设置过期时间,定期清理缓存并回写,是保证最终一致性的解决方案。

 

我们可以对存入缓存的数据设置过期时间,所有的写操作以数据库为准,对缓存操作只是尽最大努力即可。也就是说如果数据库写成功,缓存更新失败,那么只要到达过期时间,则后面的读请求自然会从数据库中读取新值然后回填缓存,达到一致性,切记,要以mysql的数据库写入库为准

4.1 可以停机的情况下

凌晨维护,服务降级

单线程,这种重量级数据操作最好不要多线程 

4.2 不停机情况下四种更新策略

4.2.1 先更新数据库在更新缓存

异常情况1

 1 先更新mysql的某商品的库存,当前商品的库存是100,更新为99个。

 

 2 先更新mysql修改为99成功,然后更新redis。

 

 3 此时假设异常出现,更新redis失败了,这导致mysql里面的库存是99而redis里面的还是100 。

 

 4  上述发生,会让数据库里面和缓存redis里面数据不一致,读到redis脏数据

异常情况2

【先更新数据库,再更新缓存】,A、B两个线程发起调用

【正常逻辑】

1 A update mysql 100

2 A update redis 100

3 B update mysql 80

4 B update redis 80

=============================

【异常逻辑】多线程环境下,A、B两个线程有快有慢,有前有后有并行

1 A update mysql 100

3 B update mysql 80

4 B update redis 80

2 A update redis 100

 =============================

最终结果,mysql和redis数据不一致,o(╥﹏╥)o,

mysql80,redis100

4.2.2 先更新缓存在更新数据库

不推荐该做法,因为业务上一般以mysql数据库作为底单数据库(类似于数据原件),所有数据以MySQL数据库为准,而redis可以理解为副本 (拷贝)

异常情况

【先更新缓存,再更新数据库】,A、B两个线程发起调用

【正常逻辑】

1 A update redis 100

2 A update mysql 100

3 B update redis 80

4 B update mysql 80

====================================

【异常逻辑】多线程环境下,A、B两个线程有快有慢有并行

A update redis  100

B update redis  80

B update mysql 80

A update mysql 100

 

----mysql100,redis80

4.2.3 先删缓存再更新数据库

异常情况

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

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

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

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

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

上述情况就会导致不一致的情形出现。 

时间
线程A
线程B
出现的问题
t1
请求A进行写操作,删除缓存成功后,工作正在mysql进行中......
t2
1 缓存中读取不到,立刻读mysql,由于A还没有对mysql更新完,读到的是旧值
2 还把从mysql读取的旧值,写回了redis
1 A还没有更新完mysql,导致B读到了旧值
2 线程B遵守回写机制,把旧值写回redis,导致其它请求读取的还是旧值,A白干了。
t3
A更新完mysql数据库的值,over
redis是被B写回的旧值,
mysql是被A更新的新值。
出现了,数据不一致问题。

总结一下:

先删除缓存,再更新数据库
如果数据库更新失败或超时或返回不及时,导致B线程请求访问缓存时发现redis里面没数据,缓存缺失,B再去读取mysql时, 从数据库中读取到旧值,还写回redis,导致A白干了,o(╥﹏╥)o
 异常解决方案:延迟双删

假设有A、B两个线程,A先把缓存进行删除,此时正在写入数据(但未完成),B进行查询操作,发现缓存内没有命令数据就到MySQL数据中进行数据查询,因为线程A还未完成更新数据,故B线程查到的为旧数据并写入到缓存中,当线程B完成以上一系列操作后,A线程完成数据更新就会把缓存的数据再次删除(延迟双删),当下一个线程来查询数据时发现缓存没有就会到数据库中重新查询,此时查询并回写的数据为最新的数据,保证了数据一致性

 延迟双删面试题

1. 这个删除该休眠多久

线程A sleep的时间,就需要大于线程B读取数据再写入缓存的时间。

 

这个时间怎么确定呢?

 第一种方法:

在业务程序运行的时候,统计下线程读数据和写缓存的操作时间,自行评估自己的项目的读数据业务逻辑的耗时,

以此为基础来进行估算。然后写数据的休眠时间则在读数据业务逻辑的耗时基础上加百毫秒即可。

 

 

这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。

 

 第二种方法:

 

新启动一个后台监控程序,比如后面要讲解的WatchDog监控程序,会加时

2. 这种同步淘汰策略,吞吐量降低怎么解决?

异步删除 

 

4.2.4 先更数据库在删除缓存 

异常问题

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

时间
线程A
线程B
出现的问题
t1
更新数据库中的值......
t2
缓存中立刻命中,此时B读取的是缓存旧值。
A还没有来得及删除缓存的值,导致B缓存命中读到旧值。
t3
更新缓存的数据,over
先更新数据库,再删除缓存
假如缓存删除失败或者来不及,导致请求再次访问redis时缓存命中, 读取到的是缓存旧值。

解决方案

1 可以把要删除的缓存值或者是要更新的数据库值暂存到消息队列中(例如使用Kafka/RabbitMQ等)。
2 当程序没有能够成功地删除缓存值或者是更新数据库值时,可以从消息队列中重新读取这些值,然后再次进行删除或更新。
3 如果能够成功地删除或更新,我们就要把这些值从消息队列中去除,以免重复操作,此时,我们也可以保证数据库和缓存的数据一致了,否则还需要再次进行重试
4 如果重试超过的一定次数后还是没有成功,我们就需要向业务层发送报错信息了,通知运维人员。

 

总结

在大多数业务场景下, 

个人建议是(仅代表我个人,不权威),优先使用先更新数据库,再删除缓存的方案(先更库→后删存)。理由如下:

 

1 先删除缓存值再更新数据库,有可能导致请求因缓存缺失而访问数据库,给数据库带来压力导致打满mysql。

 

2 如果业务应用中读取数据库和写缓存的时间不好估算,那么,延迟双删中的等待时间就不好设置。

 

 多补充一句:如果使用先更新数据库,再删除缓存的方案

如果业务层要求必须读取一致性的数据,那么我们就需要在更新数据库时,先在Redis缓存客户端暂停并发读请求,等数据库更新完、缓存值删除后,再读取数据,从而保证数据一致性,这是理论可以达到的效果,但
实际,不推荐,因为真实生产环境中,分布式下很难做到实时一致性, 一般都是最终一致性,请大家参考。

策略
高并发多线程条件下
问题
现象
解决方案
先删除redis缓存,再更新mysql
缓存删除成功但数据库更新失败
Java程序从数据库中读到旧值
再次更新数据库,重试
缓存删除成功但数据库更新中......
有并发读请求
并发请求从数据库读到旧值并回写到redis,导致后续都是从redis读取到旧值
延迟双删
先更新mysql,再删除redis缓存
数据库更新成功,但缓存删除失败
Java程序从redis中读到旧值
再次删除缓存,重试
数据库更新成功但缓存删除中......
有并发读请求
并发请求从缓存读到旧值
等待redis删除完成,这段时间有
数据不一致,短暂存在。

 

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

进程守护化

文章目录 概念引入ps细节展示什么是进程组什么是会话细节演示有关指令的处理 用户级任务和进程组的关系关系不同 什么是守护进程如何创建守护进程 代码说明如何关闭守护进程 问题 概念引入 我们在之前的章节中已将看过进程相关的概念, 本篇介绍守护进程 进程还有进程组, 作业,…

锐龙7 7800X3D与i7-14700K到底怎么选!其实很简单

从2022年的锐龙7 5800X3D到后来的锐龙7 7800X3D,笔者使用X3D处理器已有2年多的时间。站在自己的立场,我是非常希望游戏老鸟购买这类处理器的,并且也推荐了不少。 这里说的是老鸟,也就是比较懂电脑的玩家。 但是对于新手玩家而言&a…

Kali Linux 下载与安装手册

目录 Kali 是什么? 通过Kali官方网站下载 Kali 是什么? Kali Linux,前称BackTrack,是一个基于Debian的Linux发行版,专为数字取证和渗透测试而设计。它由Offensive Security Ltd.开发和维护,旨在为安全专…

HarmonyOS NEXT应用开发实战(二、封装比UniApp和小程序更简单好用的网络库)

网络访问接口,使用频次最高。之前习惯了uniapp下的网络接口风格,使用起来贼简单方便。转战到鸿蒙上后,原始网络接口写着真累啊!目标让鸿蒙上网络接口使用,简单程度比肩uniapp,比Axios更轻量级。源码量也不多…

【Parsec】一款安全高效的远程桌面软件

Parsec 是一款远程桌面软件,它允许用户通过P2P(点对点)技术远程访问和控制另一台计算机。以下是Parsec的一些主要作用、安全私密性特点以及优缺点: 作用: 远程游戏:用户可以远程访问高性能PC进行游戏&am…

记一次pyc逆向

.py文件   源代码文件。   这是开发者编写的 Python 源代码文件,包含了可执行的 Python 代码。 .pyc文件   字节码文件。   Python 源文件(.py)在执行时会被编译为字节码,并存储在 __pycache__ 目录下,文件名通…

Halcon形态学

形态学图像处理(简称形态学)是指一系列处理图像形状特征的图像处理技术。 形态学的基本思想是利用一种特殊的结构元来测量或提取输入图像中相应的形状或特征,以便进一步进行图像分析和目标识别。本章节依次对腐蚀,膨胀&#xff0…

Nacos作为注册中心和配置中心

下载安装Nacos 下载地址&#xff1a;Nacos 下载后将这个.zip文件解压 windows系统双击运行startup.cmd 注意事项 一些较新的版本可能会启动时闪退&#xff0c;解决方法为记事本编辑startuo.cmd文件 修改set MODE "standalone" Nacos注册中心 引入依赖 <dep…

动态规划算法专题(六):回文串问题

目录 1、回文子串&#xff08;"引子题"&#xff09; 1.1 算法原理 1.2 算法代码 2、最长回文子串 2.1 算法原理 2.2 算法代码 3、分割回文串 IV&#xff08;hard&#xff09; 3.1 算法原理 3.2 算法代码 4、分割字符串 II&#xff08;hard&#xff09; 4…

Spring Boot教学资源库:开发者的成长之路

2 相关技术简介 2.1Java技术 Java是一种非常常用的编程语言&#xff0c;在全球编程语言排行版上总是前三。在方兴未艾的计算机技术发展历程中&#xff0c;Java的身影无处不在&#xff0c;并且拥有旺盛的生命力。Java的跨平台能力十分强大&#xff0c;只需一次编译&#xff0c;任…

AI视频技术复活老照片-简单快捷

准备老照片 可在网上搜索“老照片”图片&#xff0c;选择人物背景全的图片 照片修复 腾讯的ARC Lab网站 https://arc.tencent.com/zh/ai-demos/faceRestoration 上传照片&#xff0c;修复后下载&#xff0c;会直接在浏览器中下载 AI视频生成 采用可灵网&#xff1a; http…

PGMP-05相关方

目录 1.主要内容 2.概括 3.相关方人员 1.主要内容 Stakeholders IdentificationStakeholders AnalysisStakeholders Engagement PlanningStakeholders EngagementStakeholder communications 2.概括 识别&#xff1a;产生相关方登记册&#xff0c;使用头脑风暴分析&#x…

深入理解Transformer的笔记记录(精简版本)----Seq2Seq → Seq2Seq with Attention

只要是符合类似的框架,都可以统称为 Encoder-Decoder 模型。 1、RNN RNN引入了隐状态h(hidden state)的概念,隐状态h可以对序列形的数据提取特征,接着再转换为输出。 x1,x2,x3,x4如: 自然语言处理问题。x1可以看做是第一个单词,x2可以看做是第二个单词,依次类推语音处…

2024 闽盾杯-黑盾赛道WP

CRYPTO 签到题-学会SM https://www.json.cn/encrypt/sm3 题目要求小写所以需要转换一下 或者脚本&#xff1a; import hashlib message "heidun2024" hash_object hashlib.new(sm3) hash_object.update(message.encode(utf-8)) hash_value hash_object.hexdigest(…

AI助力智慧农田作物病虫害监测,基于YOLOv9全系列【yolov9/t/s/m/c/e】参数模型开发构建花田作物种植场景下棉花作物常见病虫害检测识别系统

智慧农业是一个很大的应用市场&#xff0c;将当下如火如荼的AI模型技术与现实的农业生产场景相结合能够有效提升生产效率&#xff0c;农作物在整个种植周期中有很多工作需要进行&#xff0c;如&#xff1a;浇水、施肥、除草除虫等等&#xff0c;传统的农业作物种植生产管理周期…

带你走近CCV(一)

从事多媒体互动行业8年了&#xff0c;最近才想着自己可以独自写一个识别软件&#xff0c;应该说想把公司里的识别统统临摹一遍&#xff0c;这样在接外包的时候可以游刃有余了 什么是CCV&#xff1f; CCV是一个建立在openCV基础上的一个开源的架构&#xff0c;其全称是Communit…

SpringBoot教程(二十四) | SpringBoot实现分布式定时任务之Quartz(多数据源配置)

SpringBoot教程&#xff08;二十四&#xff09; | SpringBoot实现分布式定时任务之Quartz&#xff08;多数据源配置&#xff09; 前言多数据源配置引入aop依赖1. properties配置多数据源2. 创建数据源枚举类3. 线程参数配置类4. 数据源动态切换类5. 多数据源配置类HikariCP 版本…

Java基础(2) 之面向对象

文章目录 Java基础(2) 之面向对象1.对象2.类类的注意事项 3.this关键字4.构造器注意 5.封装性6.实体JavaBean实体类 7.成员变量和局部变量的区别8.staticstatic修饰成员变量static修饰成员方法static的注意事项工具类单例设计模式 9.代码块静态代码块实例代码块 10.继承权限修饰…

Springboot——使用poi实现excel动态图片导入解析

文章目录 前言依赖引入导入实现方式一方式二 前言 最近要实现一个导入导出的功能点&#xff0c;需要能将带图片的列表数据导出到excel中&#xff0c;且可以导入带图片的excel列表数据。 考虑到低代码平台的表头与数据的不确定性&#xff0c;技术框架上暂定使用Apache-POI。 …

java 自定义填充excel并导出

首先在resources下面放一个excel模板 1. 方法签名和请求映射 RequestMapping(value "/ExportXls") public ResponseEntity<byte[]> rwzcExportXls(HttpServletRequest request, RequestBody JSONArray jsonArray) throws IOException { RequestMapping(val…