2023-07-03:讲一讲Redis缓存的数据一致性问题和处理方案。

答案2023-07-03:

数据一致性

当使用缓存时,无论是在本地内存中缓存还是使用 Redis 等外部缓存系统,会引入数据同步的问题。下面以 Tomcat 向 MySQL 中进行数据的插入、更新和删除操作为例,来说明具体的过程。

分析下面几种解决方案的数据同步方案:

1.先更新缓存,再更新数据库:先更新缓存可以提高读取性能,但如果更新缓存成功而更新数据库失败,可能导致数据不一致。

2.先更新数据库,再更新缓存:确保数据的持久性,但如果更新数据库成功而更新缓存失败,也可能导致数据不一致。

3.先删除缓存,后更新数据库:通过先删除缓存,再更新数据库的方式,可以在数据更新后保证数据的一致性,但会降低读取操作的性能。

4.先更新数据库,后删除缓存:确保数据的持久性,并在更新数据库成功后再删除缓存,以保持数据的一致性。

新增数据类

对于新增数据的情况,数据会直接写入数据库,无需对缓存进行操作。在这种情况下,缓存中本身就没有新增数据,而数据库中保存的是最新值。因此,缓存和数据库的数据是一致的。

更新缓存类

1、先更新缓存,再更新DB

我们通常不考虑这个方案,因为存在以下问题:即使在更新缓存成功后,若出现更新数据库时的异常,会导致缓存中的数据与数据库数据完全不一致。由于缓存数据一直存在,这种不一致性很难察觉到。

2、先更新DB,再更新缓存

我们一般不考虑先更新数据库再更新缓存的方案,与第一个方案存在相同的问题。数据库更新成功但缓存更新失败时,仍然会导致数据不一致的问题。此外,这种方案还存在以下问题:

  1. 并发问题:当有请求A和请求B同时进行更新操作时,可能出现以下情况:线程A先更新数据库,然后线程B也更新了数据库,随后线程B更新了缓存,最后线程A也更新了缓存。这导致了请求A应该先更新缓存,但由于网络等原因,请求B却比请求A更早更新了缓存,从而产生脏数据。

  2. 业务场景问题:如果写数据库的操作比读数据的操作更频繁,采用这种方案会导致数据还没有被读取,就频繁更新缓存,从而浪费性能。

除了更新缓存,我们还可以考虑删除缓存的方案。具体选择更新缓存还是淘汰缓存取决于“更新缓存的复杂度”。如果更新缓存的成本较低,我们更倾向于更新缓存以提高缓存命中率;而如果更新缓存的代价较高,我们则更倾向于淘汰缓存。

删除缓存类

3、先删除缓存,后更新DB

该方案也会出问题,具体出现的原因如下。

1、此时来了两个请求,请求 A(更新操作) 和请求 B(查询操作)

2、请求 A 会先删除 Redis 中的数据,然后去数据库进行更新操作;

3、此时请求 B 看到 Redis 中的数据时空的,会去数据库中查询该值,补录到 Redis 中;

4、但是此时请求 A 并没有更新成功,或者事务还未提交,请求B去数据库查询得到旧值;

5、那么这时候就会产生数据库和 Redis 数据不一致的问题。

如何解决呢?其实最简单的解决办法就是延时双删的策略。就是

(1)先淘汰缓存

(2)再写数据库

(3)休眠1秒,再次淘汰缓存

这段伪代码就是“延迟双删”

redis.delKey(X)
db.update(X)
Thread.sleep(N)
redis.delKey(X)

这么做,可以将1秒内所造成的缓存脏数据,再次删除。

那么,这个1秒怎么确定的,具体该休眠多久呢?

针对上面的情形,读该自行评估自己的项目的读数据业务逻辑的耗时。然后写数据的休眠时间则在读数据业务逻辑的耗时基础上,加几百ms即可。这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。

但是上述的保证事务提交完以后再进行删除缓存还有一个问题,就是如果你使用的是** Mysql ****的读写分离的架构**的话,那么其实主从同步之间也会有时间差。

此时来了两个请求,请求 A(更新操作) 和请求 B(查询操作)

请求 A 更新操作,删除了

Redis,

请求主库进行更新操作,主库与从库进行同步数据的操作,

请 B 查询操作,发现 Redis

中没有数据,

去从库中拿去数据,此时同步数据还未完成,拿到的数据是旧数据。

此时的解决办法有两个:

1、还是使用双删延时策略。只是,睡眠时间修改为在主从同步的延时时间基础上,加几百ms。

2、就是如果是对 Redis

进行填充数据的查询数据库操作,那么就强制将其指向主库进行查询。

继续深入,采用这种同步淘汰策略,吞吐量降低怎么办?

那就将第二次删除作为异步的。自己起一个线程,异步删除。这样,写的请求就不用沉睡一段时间后了,再返回。这么做,加大吞吐量。

继续深入,第二次删除,如果删除失败怎么办?

所以,我们引出了,下面的第四种策略,先更新数据库,再删缓存。

4、先更新DB,后删除缓存

Cache Aside模式是一种常用的缓存处理方式。在读取数据时,先检查缓存,如果缓存中存在数据,则直接返回;如果缓存中不存在,则从数据库中读取,并将数据写入缓存,最后返回响应。在更新数据时,先更新数据库,然后再删除缓存。

通常情况下,我们更倾向于使用删除缓存的操作,因为删除缓存的速度比在数据库中更新数据的速度更快,能更有效地避免数据不一致的问题。通过延时双删的处理方式,可以进一步减少缓存不一致性的可能性。

2023-07-03:讲一讲Redis缓存的数据一致性问题和处理方案。的更多相关文章

  1. redis缓存与数据一致性

    目录 缓存 缓存穿透 缓存雪崩(缓存失效) 缓存击穿(热点key) 缓存并发竞争(并发set) 数据一致性 缓存(双写)一致性 Redis集群(Redis-cluster)一致性原理 哨兵(Senti ...

  2. Redis缓存你必须了解的!

    不管你是从事Python.Java.Go.PHP.Ruby等等… Redis都应该是一个比较熟悉的中间件.而大部分经常写业务代码的程序员,实际工作中或许只用到了set value.get value两 ...

  3. 分布式Redis缓存串讲(一)

    互联网应用的基石 现在流量稍微大些的网站,都会采取Redis.基于Redis的内存缓存特性,可以大幅度降低数据库的访问量,大大提升了网站的并发能力,充当数据库的削量先锋.既然Redis这么重要,我们从 ...

  4. RabbitMQ队列/Redis缓存

    一.RabbitMQ队列 RabbitMQ安装(Centos7安装):1.安装依赖:yum install socat (不安装会报错)2.下载rpm包:wget http://www.rabbitm ...

  5. Redis缓存穿透、缓存雪崩、redis并发问题 并发竞争key的解决方案 (阿里)

    阿里的人问我 缓存雪崩(大量数据在同一时间过期了)了如何处理,缓存击穿了如何处理,回答的很烂,做了总结: 把redis作为缓存使用已经是司空见惯,但是使用redis后也可能会碰到一系列的问题,尤其是数 ...

  6. 快速搭建Redis缓存数据库

    之前一篇随笔——Redis安装及主从配置已经详细的介绍过Redis的安装于配置.本文要讲的是如何在已经安装过Redis的机器上快速的创建出一个新的Redis缓存数据库. 一.环境介绍 1) Linux ...

  7. ABP入门系列(13)——Redis缓存用起来

    ABP入门系列目录--学习Abp框架之实操演练 源码路径:Github-LearningMpaAbp 1. 引言 创建任务时我们需要指定分配给谁,Demo中我们使用一个下拉列表用来显示当前系统的所有用 ...

  8. Spring+SpringMVC+MyBatis+easyUI整合进阶篇(十四)Redis缓存正确的使用姿势

    作者:13 GitHub:https://github.com/ZHENFENG13 版权声明:本文为原创文章,未经允许不得转载. 简介 这是一篇关于Redis使用的总结类型文章,会先简单的谈一下缓存 ...

  9. Redis 缓存失效和回收机制续

    二.Redis Key失效机制 Redis的Key失效机制,主要借助借助EXPIRE命令: EXPIRE key 30 上面的命令即为key设置30秒的过期时间,超过这个时间,我们应该就访问不到这个值 ...

  10. redis缓存雪崩、缓存穿透、数据库和redis数据一致性

    一.缓存雪崩 回顾一下我们为什么要用缓存(Redis):减轻数据库压力或尽可能少的访问数据库. 在前面学习我们都知道Redis不可能把所有的数据都缓存起来(内存昂贵且有限),所以Redis需要对数据设 ...

随机推荐

  1. 和我一起学 Three.js【初级篇】:1. 搭建 3D 场景

    欢迎关注「前端乱步」公众号,我会在此分享 Web 开发技术,前沿科技与互联网资讯. 0. 系列文章合集 本系列第 6,7 章节支持微信公众号内付费观看,将在全系列文章点赞数+评论数 >= 500 ...

  2. wpf RelativeSource绑定

    RelativeSource有四种类型 Self FindAncestor TemplatedParent PreviousData a.Self Self用于绑定源和绑定目标相同的场景中.对象的一个 ...

  3. ros-python学习样例笔记

    1.通信基本原理介绍 待写 2.三种通信方式的程序样例(python版) 2.1 topic 通信方式(非自定义和自定义) 2.1.1 创建工作空间和topic功能包 在ubuntu中打开命令行,输入 ...

  4. MySQL(十一)索引的分类和创建原则

    索引的创建与设计原则 1 索引的声明与使用 1.1 索引的分类 ​ MySQL索引包括普通索引.唯一性索引.全文索引.单列索引.多列索引和空间索引 按照逻辑结构划分,主要有四种:普通索引.唯一性索引. ...

  5. 从Chat-GPT看爆火技术概念及医疗领域科技与应用场景

    作者:京东健康 陈刚 一.前言 最近OpenAI在官网上宣告了多模态大模型 GPT-4 的诞生,它可能是迄今为止最好的多模态模型. 主要更新内容如下: 1. 逻辑分析能力更加全面.「考试」能力大幅提升 ...

  6. Indent----- IndentationError: unexpected indent

    Unexpected indent 错误 注意,Python 中实现对代码的缩进,可以使用空格或者 Tab 键实现.但无论是手动敲空格,还是使用 Tab 键,通常情况下都是采用 4 个空格长度作为一个 ...

  7. 指针和引用(pointer and reference),传值和传址

    pass by adress pass by reference和pass by pointer的共同点都在于传址,都是对于对象的地址的复制,而不会对对象进行产生副本的操作. pass by refe ...

  8. python-SSTI模板注入

    一.python_SSTI模板注入介绍 ssti漏洞成因 ssti服务端模板注入,ssti主要为python的一些框架 jinja2 mako tornado django,PHP框架smarty t ...

  9. vue中使用西瓜视频api

    https://v2.h5player.bytedance.com/en/api/ 1 npm install xgplayer 1 <div id="mse">< ...

  10. [C++核心编程] 4.7 多态

    文章目录 4.7 多态 4.7.1 多态的基本概念 4.7.2 多态案例一-计算器类 4.7.3 纯虚函数和抽象类 4.7.4 多态案例二-制作饮品 4.7.5 虚析构和纯虚析构 4.7.6 多态案例 ...