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


分析下面几种解决方案的数据同步方案:
1.先更新缓存,再更新数据库:先更新缓存可以提高读取性能,但如果更新缓存成功而更新数据库失败,可能导致数据不一致。
2.先更新数据库,再更新缓存:确保数据的持久性,但如果更新数据库成功而更新缓存失败,也可能导致数据不一致。
3.先删除缓存,后更新数据库:通过先删除缓存,再更新数据库的方式,可以在数据更新后保证数据的一致性,但会降低读取操作的性能。
4.先更新数据库,后删除缓存:确保数据的持久性,并在更新数据库成功后再删除缓存,以保持数据的一致性。
新增数据类
对于新增数据的情况,数据会直接写入数据库,无需对缓存进行操作。在这种情况下,缓存中本身就没有新增数据,而数据库中保存的是最新值。因此,缓存和数据库的数据是一致的。
更新缓存类
1、先更新缓存,再更新DB
我们通常不考虑这个方案,因为存在以下问题:即使在更新缓存成功后,若出现更新数据库时的异常,会导致缓存中的数据与数据库数据完全不一致。由于缓存数据一直存在,这种不一致性很难察觉到。

2、先更新DB,再更新缓存
我们一般不考虑先更新数据库再更新缓存的方案,与第一个方案存在相同的问题。数据库更新成功但缓存更新失败时,仍然会导致数据不一致的问题。此外,这种方案还存在以下问题:
并发问题:当有请求A和请求B同时进行更新操作时,可能出现以下情况:线程A先更新数据库,然后线程B也更新了数据库,随后线程B更新了缓存,最后线程A也更新了缓存。这导致了请求A应该先更新缓存,但由于网络等原因,请求B却比请求A更早更新了缓存,从而产生脏数据。
业务场景问题:如果写数据库的操作比读数据的操作更频繁,采用这种方案会导致数据还没有被读取,就频繁更新缓存,从而浪费性能。
除了更新缓存,我们还可以考虑删除缓存的方案。具体选择更新缓存还是淘汰缓存取决于“更新缓存的复杂度”。如果更新缓存的成本较低,我们更倾向于更新缓存以提高缓存命中率;而如果更新缓存的代价较高,我们则更倾向于淘汰缓存。
删除缓存类
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缓存的数据一致性问题和处理方案。的更多相关文章
- redis缓存与数据一致性
目录 缓存 缓存穿透 缓存雪崩(缓存失效) 缓存击穿(热点key) 缓存并发竞争(并发set) 数据一致性 缓存(双写)一致性 Redis集群(Redis-cluster)一致性原理 哨兵(Senti ...
- Redis缓存你必须了解的!
不管你是从事Python.Java.Go.PHP.Ruby等等… Redis都应该是一个比较熟悉的中间件.而大部分经常写业务代码的程序员,实际工作中或许只用到了set value.get value两 ...
- 分布式Redis缓存串讲(一)
互联网应用的基石 现在流量稍微大些的网站,都会采取Redis.基于Redis的内存缓存特性,可以大幅度降低数据库的访问量,大大提升了网站的并发能力,充当数据库的削量先锋.既然Redis这么重要,我们从 ...
- RabbitMQ队列/Redis缓存
一.RabbitMQ队列 RabbitMQ安装(Centos7安装):1.安装依赖:yum install socat (不安装会报错)2.下载rpm包:wget http://www.rabbitm ...
- Redis缓存穿透、缓存雪崩、redis并发问题 并发竞争key的解决方案 (阿里)
阿里的人问我 缓存雪崩(大量数据在同一时间过期了)了如何处理,缓存击穿了如何处理,回答的很烂,做了总结: 把redis作为缓存使用已经是司空见惯,但是使用redis后也可能会碰到一系列的问题,尤其是数 ...
- 快速搭建Redis缓存数据库
之前一篇随笔——Redis安装及主从配置已经详细的介绍过Redis的安装于配置.本文要讲的是如何在已经安装过Redis的机器上快速的创建出一个新的Redis缓存数据库. 一.环境介绍 1) Linux ...
- ABP入门系列(13)——Redis缓存用起来
ABP入门系列目录--学习Abp框架之实操演练 源码路径:Github-LearningMpaAbp 1. 引言 创建任务时我们需要指定分配给谁,Demo中我们使用一个下拉列表用来显示当前系统的所有用 ...
- Spring+SpringMVC+MyBatis+easyUI整合进阶篇(十四)Redis缓存正确的使用姿势
作者:13 GitHub:https://github.com/ZHENFENG13 版权声明:本文为原创文章,未经允许不得转载. 简介 这是一篇关于Redis使用的总结类型文章,会先简单的谈一下缓存 ...
- Redis 缓存失效和回收机制续
二.Redis Key失效机制 Redis的Key失效机制,主要借助借助EXPIRE命令: EXPIRE key 30 上面的命令即为key设置30秒的过期时间,超过这个时间,我们应该就访问不到这个值 ...
- redis缓存雪崩、缓存穿透、数据库和redis数据一致性
一.缓存雪崩 回顾一下我们为什么要用缓存(Redis):减轻数据库压力或尽可能少的访问数据库. 在前面学习我们都知道Redis不可能把所有的数据都缓存起来(内存昂贵且有限),所以Redis需要对数据设 ...
随机推荐
- Go 语言切片是如何扩容的?
原文链接: Go 语言切片是如何扩容的? 在 Go 语言中,有一个很常用的数据结构,那就是切片(Slice). 切片是一个拥有相同类型元素的可变长度的序列,它是基于数组类型做的一层封装.它非常灵活,支 ...
- 写一个 Hello SpringBoot2 项目
需求:向浏览发送/hello请求,并响应 Hello,Spring Boot 2 解决: 项目目录:controller层.Main启动项.pom.xml controller层:写好逻辑跳转,当浏览 ...
- 在smt贴片加工中手工焊接和机器焊接的区别
在smt贴片加工领域,都需要将电子元件贴装在pcb板表面并进行焊接的,常用的焊接方式分为两种:手动焊接和全自动机器焊接,而常用的焊接机器有回流焊机和波峰焊机,那你知道他们的区别是什么吗?安徽英特丽带你 ...
- C# 如何设计一个好用的日志库?【架构篇】
〇.前言 相信你在实际工作期间经常遇到或听到这样的说法: "我现在加一下日志,等会儿你再操作下." "只有在程序出问题以后才会知道打一个好的日志有多么重要.&qu ...
- 关于聚合根,领域事件的那点事---深入浅出理解DDD
作者:京东物流 赵勇萍 前言 最近有空会跟同事讨论DDD架构的实践落地的情况,但真实情况是,实际中对于领域驱动设计中的实体,值对象,聚合根,领域事件这些战术类的实践落地,每个人理解依然因人而异,大概率 ...
- CUDA 的随机数算法 API
参考自 Nvidia cuRand 官方 API 文档 一.具体使用场景 如下是是在 dropout 优化中手写的 uniform_random 的 Kernel: #include <cuda ...
- sqlilabs第一关
首先打开网页,进行注入点的测试 输入?id=1 and 1=1发现1=2的时候没有进行报错,有两种可能,一种是不能注入,第二种是字符型可以通过对字符型里面的''进行闭合,输入'and 1=1--+发现 ...
- etcd:增加30%的写入性能
etcd:增加30%的写入性能 本文最终的解决方式很简单,就是将现有卷升级为支持更高IOPS的卷,但解决问题的过程值得推荐. 译自:etcd: getting 30% more write/s 我们的 ...
- 【Docker】容器管理
一.容器生命周期及启动过程 1.容器生命周期 2.容器启动过程 二.容器管理命令 Usage: docker [OPTIONS] COMMAND A self-sufficient runtime f ...
- BS系统自动更新的实现
背景: 我公司做的考试系统(基于java开发的BS系统)是卖给学校的,随着客户数量增多,日常版本升级.远程维护工作占了程序员很多时间,遂考虑实现系统自动化更新. 要解决的问题及解决方案: 1.什么时候 ...