面试题: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.rhkb.cn/news/448133.html

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

相关文章

微知-Mellanox驱动中的iSCSI是什么?有哪三种网络存储有哪三种?iSER是什么?(iSCSI协议(总线),SAN 存储区域网络)

背景 本文根据Mellanox网卡驱动中关于iSCSI模块,来介绍iSCSI是什么?该技术发展演进背景? 关于iSCSI iSCSI是一种协议,SCSI是总线。比如常说的SAS(Serial Attach SCSI)存储盘对比与家用的SATA&#xff0…

Uiautomator2与weditor配置一直报错咋办

作者在配置这两个的时候绞尽脑汁了,u2的init总是报错并且无法自动在手机上安装atx,weditor可以打开但是只要对元素操作或者任意操作就会让你去重新init,搞得作者焦头烂额,而且网上各种各样的报错信息眼花缭乱,作者几乎…

NVIDIA NIM平台如何打造AI图表识别系统

NVIDIA NIM是一套易于使用的推理微服务,旨在加速企业中性能优化的生成式 AI 模型的部署。 NIM 推理微服务可以部署在任何地方,从工作站和本地到云,提供企业控制自己的部署选择并确保数据安全。它还提供行业领先的延迟和吞吐量,实现…

使用Windows创建一个MFC应用【带界面】

MFC使用教程【对初学者保姆型友好!】 目录 前提条件 1:创建MFC应用程序 2. 项目结构解读 引用 外部依赖项 头文件 源文件 资源文件 文件功能详解 项目的主要流程 步骤2:配置OpenCV 安装OpenCV 包含目录与库文件 步骤3&#xff1…

云卓H30:引领科技与性能的完美融合!

在科技日新月异的今天,一款集高性能与便捷操作于一体的手持地面站成为了无人机、机器人等智能设备的得力助手。云卓H30手持地面站,凭借其搭载的高通骁龙660处理器,在多个适用场景中展现出了卓越的实力。 高通骁龙660,这款先进的移…

Python 如何处理大规模数据库表的迁移与数据迁移的高效执行

Python 如何处理大规模数据库表的迁移与数据迁移的高效执行 引言 在现代应用开发中,随着业务需求的增长,数据库表结构和数据往往需要进行迁移和更新。迁移(Migration)是指对数据库表的结构、数据类型、索引、约束等进行修改或更新…

Docker 安装sql server 登陆失败

错误: Sqlcmd: Error: Microsoft ODBC Driver 18 for SQL Server : SSL Provider: [error:0A000086:SSL routines::certificate verify failed:self-signed certificate]. Sqlcmd: Error: Microsoft ODBC Driver 18 for SQL Server : Client unable to establish co…

UE5 TimeLine入门

UE5 TimeLine入门 时间轴曲线 共计三个关键帧(0,0)(1.5,10) (3,0) 蓝图 1.按下空格键执行。 2.时间轴TimeLine函数。 3.动画播放结束后执行。 4.每一帧都执行。

单片机原理及应用笔记:单片机的结构原理与项目实践

作者介绍 李婷婷,女,银川科技学院计算机与人工智能学院,2022级计算机与科学技术9班本科生,单片机原理及应用课程第五组。 指导老师:王兴泽 电子邮箱:365349930qq.com 前言 本篇文章是参考《单片机原理…

rk3568 , rk3588 , rknpu2 sdk , rknn-toolkit2, rknn-toolkit2-lite 的了解

rknpu2 sdk 与 rknn-toolkit 的区别。 网上的截图: 总结: rknpu2 是针对 C接口的, rknn toolkit2 是针对 Python接口的。 至于 连不连板, 是不是 拷贝, 那不重要。 然后是 rknn rootlkit2 与 rknn toolkit2 li…

数据结构算法题:栈与队列的使用(一)

目录 用队列实现栈题目解题思路代码实现创建栈的结构体栈的初始化入栈出栈获取栈顶数据判断栈是否为空销毁栈 用队列实现栈 题目 题目描述: 示例: 解题思路 题目要求使用两个队列实现栈的入栈、出栈、获取栈顶元素、检查栈是否为空栈的基本操作。 …

答题pk小程序的技术特点和性能优势分析

答题小程序是一种在移动设备上运行的应用程序,旨在提供各种类型的答题体验。以下是答题小程序的一些特点和优势: 一、特点 多样化的题目类型: 包括选择题、填空题、判断题等常见题型,还可能有简答题、论述题等更具挑战性的题型。…

健康推荐系统:SpringBoot技术实现

3系统分析 3.1可行性分析 通过对本基于智能推荐的卫生健康系统实行的目的初步调查和分析,提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本基于智能推荐的卫生健康系统采用SSM框架&#…

Spire.PDF for .NET【页面设置】演示:在 C#/VB.NET 中创建 PDF 小册子

当人们打印大型 PDF 文档时,PDF 小册子非常有用。它在书籍、报纸和杂志编辑中特别受欢迎。本节将介绍一种通过C#、VB.NET 中的.NET PDF组件创建 PDF 小册子的非常简单的方法。 Spire.PDF for .NET 是一款独立 PDF 控件,用于 .NET 程序中创建、编辑和操作…

[含文档+PPT+源码等]精品基于django实现的原生Andriod天气信息的着装搭配系统

基于Django实现的原生Android天气信息的着装搭配系统背景,可以从以下几个方面进行详细阐述: 一、技术背景 Django框架: Django是一个高级的Python Web框架,它鼓励快速开发和干净、实用的设计。Django框架具有强大的数据库抽象层、…

深入了解EasyNVR及EasyNVS,EasyNVR连接到EasyNVS当显示授权超时如何解决?又因为什么原因?

我们先来了解NVR批量管理软件/平台EasyNVR,它深耕市场多年,为用户提供多种协议,兼容多种厂商设备,包括但不限于支持海康,大华,宇视,萤石,天地伟业,华为设备。 NVR录像机…

14.JVM对象创建与内存分配机制深度剖析

一、对象的创建 1.类加载检查 当虚拟机接受到一条new指令时,会去检查这个指令的参数是否能在常量池种定位到一个符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化。如果没有则进行类的加载过程; 2.分配内存 在类加载检…

【Unity实战篇】 接入百度翻译,实现文本自动翻译功能

前言【Unity实战篇】 接入百度自动翻译,实现文本自动翻译功能一、获取百度翻译开发平台的APPID和密钥二、Unity中接入自动翻译功能三、Unity中实现自动翻译文本Text功能总结前言 日常在做项目的过程中,游戏本地化几乎已经成为必不可少的一步。本篇文章将演示怎样在Unity中接入…

数据质量差的代价是什么?

如今,许多数字企业都认为自己是数据驱动的。通过各种软件解决方案,数据无处不在,收集起来也非常方便,这使得企业能够被动地收集大量数据,并将其应用于决策制定。 然而,人们往往很容易在不考虑数据质量的情…

新手爬虫DAY1

这个错误信息表明在你的Python程序中,re.search() 函数没有找到预期的匹配项,因此返回了 None。当你尝试在 None 对象上调用 group(1) 方法时,Python 抛出了一个 AttributeError。 具体来说,错误发生在 pc.py 文件的第6行&#x…