【Redis知识点总结】(四)——如何保证缓存与数据库中的数据一致性

Redis知识点总结(四)——如何保证缓存与数据库中的数据一致性

  • 更新缓存
  • 删除缓存
    • 先删除缓存后更新数据库
    • 先更新数据库后删除缓存
  • 使用canal
  • 总结

面试会经常遇到这种问题:你们如何保证缓存与数据库中的数据一致性?或者是:你们如果保证缓存与数据库的双写一致性?

其实这种问题本身就很矛盾,使用缓存的目的,本身就是牺牲一定的强一致性,追求性能的提升,如果真有场景是要保证缓存和数据库一致的,就不适合用缓存。但是既然面试官问到了,我们还是要答一下。

在使用缓存的时候,如果发生更新数据库的操作,我们可以删除缓存,也可以更新缓存。

更新缓存

我认为更新缓存是不可取的,原因有二:

  1. 如果这个缓存是个冷门数据,后续都不会查询到,那么这个更新就是多余的,还会占用内存空间
  2. 缓存和数据库都要更新,还要保证一致性,那么只能用事务,这样性能就会下降,违背了使用缓存的初衷

在这里插入图片描述

但是有一种情况是可以使用更新缓存这种策略的,就是一致性要求不高但是更新的数据是一个热点数据,那我们可以在更新数据库后,马上更新缓存,这样就不会因为有缓存缺失而造成大量的请求打向数据库,也就是缓存击穿的问题。即使更新数据库成功了,但是缓存更新失败也没关系,因为前提是一致性要求不高。

在这里插入图片描述

但是面试官问的是缓存与数据库如果保证一致性,那就不符合一致性要求不高的前提,所以更新缓存这种策略就不用考虑了。

删除缓存

再来看下删除缓存这种策略,我们可以先删缓存在更新数据库,也可以先更新数据库再删除缓存。

先删除缓存后更新数据库

先删缓存后更新数据库这种方案,有两种失败的情况:

  1. 删缓存失败
  2. 删缓存成功,更新数据库失败

如果删除缓存失败,那么就返回更新失败,此时数据库与缓存还是一致的;如果删缓存成功,但是更新数据库失败,那么也返回更新失败,此时只是缓存中没数据,下次查询的时候发现缓存缺失,从数据库中查询加载到缓存中,缓存和数据库还是一致的。这样,看起来好像没什么问题。

在这里插入图片描述

但是这种做法有一个潜在的问题,当缓存的数据的并发访问量比较大的时候,有可能出现如下这种情况:

在这里插入图片描述

线程1发起了一个更新操作,而线程2发起了以查询操作,目标都是同一份数据。线程1首先删除了缓存,但是迟迟没有更新数据库成功,而此时线程2进来了,线程2查询缓存发现缓存缺失,于是查询数据库并加载到缓存,但由于线程1没来得及更新数据库,所以此时缓存中的数据是旧的。随后线程1才更新数据库成功,此时缓存与数据库的数据就不一致了。

解决这种问题的办法,就是使用延迟双删的机制:

在这里插入图片描述

线程1在更新数据库成功后,sleep一段时间,然后再次删除缓存,就能把线程2加载到缓存中的旧值给删掉。但是这个sleep的时间长度不好把握,如果时间短了,可能在线程2加载旧值到缓存前,线程1就醒来了,那么缓存中的旧值还是没删,如果时间长了,又会影响数据更新的性能,数据已经更新成功了,但更新结果迟迟未返回。因此,一般情况下这种延时双删的机制也很少使用,进而先删缓存的这种做法也很少使用。

先更新数据库后删除缓存

再来看看先更新数据库,后删除缓存的做法。

如果更新数据库成功,然后删除缓存成功,那么缓存和数据库是能保证一致性的,但是在更新数据库成功之后,在删除缓存之前,其他线程查询到的还是旧值。

在这里插入图片描述

但是缓存不一致只是在更新数据库成功后,删除缓存成功之前的这一段时间内,如果不是要求强一致性的场景,都是可以接受的。

再看一下更新数据库或删除缓存不成功的情况:先更新数据库,如果更新失败了,那么就返回更新失败,此时缓存与数据库中的数据还是一致的;如果更新数据库成功,但是删除缓存失败,那么缓存与数据库的值是不一致。

在这里插入图片描述

但是我们可以给缓存添加一个过期时间,时间到了也会自动删除,那么我们就容忍一段时间的不一致,这种做法适用于一致性要求不高,只需要保证最终一致性的场景。

在这里插入图片描述

但是如果一致性要求非常高,不能容忍这一段时间的数据不一致,那么我们可以把要删除的key添加到队列中,然后起一个线程异步监听该队列,不断重试删除缓存,直到成功为止。

在这里插入图片描述

这种做法虽然还是没有保证绝对的一致性,但是容忍的不一致性时间更短了,更适合一致性要求较高的场景,但是引入了异步线程和队列,复制度就提升了。

如果再变态一点的,就是要保证绝对的一致,不能容忍一点点的不一致,并且连更新数据库成功后删除缓存成功之前的这一段时间的不一致也不能容忍,那么只能通过事务去保证。

在这里插入图片描述

但是这样一来,性能就会急剧下降,违背了使用缓存的初衷。

使用canal

还有一种保证缓存与数据库一致性的方案就是使用canal。

canal是基于MySQL的binlog日志进行数据同步的一个工具,它伪装成MySQL主从同步中的一个Slave节点,向MySQL主节点发起binlog同步的请求,接收到binlog后,canal就可以把接收到的binlog进行解析与处理,然后把数据同步到下游。

我们配置canal监听MySQL的binlog,然后同步数据到redis,这样就可以实现缓存与数据库的一致性。

在这里插入图片描述

当然,这种方案也不是强一致的,因为从数据库写成功,dump出binlog,到canal成功同步到redis,是存在一点点时差的。

总结

最后总结一下比较靠谱的几种做法。

如果是强一致性的场景,是不适合使用缓存的,那么最好就不要使用缓存了。如果遇到了即要求强一致性,又追求高性能的场景,那就太变态了。

如果是对一致性要求较高,但又不是强一致性,那可以使用canal同步的方案,正常情况下canal读取binlog同步数据到redis这个过程,处理是非常快的。

如果对一致性要求不高,可以采用先更新数据库,后删除缓存的机制,并且在查询数据库加载数据到缓存时,给缓存设置一个过期时间。这样,即使出现不一致,也只需容忍一段时间的不一致,等缓存过期时间到,缓存就会失效,可以到达最终一致性。

在这里插入图片描述

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

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

相关文章

*波动数列c++

题目 输入样例: 4 10 2 3输出样例: 2样例解释 两个满足条件的数列分别是2 4 1 3和7 4 1 -2。 思路 上来先理解题意,本题求的是“长度为n 总和为s的……数列的数目”。 假设第一项为x,增加 a 或者减少 b用di表示,…

【Spring Boot 源码学习】深入应用上下文初始化器实现

《Spring Boot 源码学习系列》 深入应用上下文初始化器实现 一、引言二、往期内容三、主要内容3.1 spring-boot 子模块中内置的实现类3.1.1 ConfigurationWarningsApplicationContextInitializer3.1.2 ContextIdApplicationContextInitializer3.1.3 DelegatingApplicationConte…

【智能算法】斑鬣狗优化算法(SHO)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过。 3.代码实现4.参考文献 1.背景 2017年,Dhiman等人受到斑鬣狗自然狩猎行为启发,提出了斑鬣狗优化算法(Spotted Hyena Optimizer, SHO)。 2.算法原理 2.1算法思想 SHO将斑鬣狗狩猎行为分为围捕-狩猎-进攻三…

Python入门(三)

序列 序列是有顺序的数据集合。序列包含的一个数据被称为元素,序列可以由一个或多个元素组成,也是可以没有任何元素的空序列。 序列的类型 元组(定值表):一旦建立,各个元素不可再更变,所以一…

python-0008-修改django数据库为mysql

操作系统 centos7 执行 在虚拟环境中执行: pip3 install mysqlclient2.2.4 -i https://mirrors.aliyun.com/pypi/simple无法安装问题 如果安装mysqlclient时提示找不到对应的版本,或者编译失败,请退出虚拟环境,执行以下操作&…

2024华为春招Django面试题大全,最全知识点揭秘,面试必备!

为了帮助广大求职者更好地准备即将到来的面试,本文精心编撰了一系列涵盖InnoDB存储引擎关键知识点的面试题。这些问题不仅覆盖了InnoDB的基础知识,如其ACID特性、索引设计、锁机制等,还涵盖了性能优化、备份恢复策略等高级话题,旨…

【Spring Boot 3】【JSON】读取JSON文件

【Spring Boot 3】【JSON】读取JSON文件 背景介绍开发环境开发步骤及源码工程目录结构总结背景 软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术总是要花…

简单函数_短信计费

任务描述 用手机发短信,一条短信资费为0.1元,但限定一条短信的内容在70个字以内(包括70个字)。如果你一次所发送的短信超过了70个字,则会按照每70个字一条短信的限制把它分割成多条短信发送。假设已经知道你当月所发送…

Wireshark抓包工具的使用

提示:本文为学习记录,若有错误,请联系作者,谦虚受教 文章目录 前言一、下载二、首页三、使用1.读入数据2.分析数据3.筛选IP4.保存数据 四、过滤器表达式五、TCP总结 前言 低头做事,抬头看路。 一、下载 下载路径wire…

【论文笔记合集】LSTNet之循环跳跃连接

本文作者: slience_me LSTNet 循环跳跃连接 文章仅作为个人笔记 论文链接 文章原文 LSTNet [25] introduces convolutional neural networks (CNNs) with recurrent-skip connections to capture the short-term and long-term temporal patterns. LSTNet [25]引入…

【Java刷题篇】串联所有单词的子串

这里写目录标题 📃1.题目📜2.分析题目📜3.算法原理🧠4.思路叙述✍1.进窗口✍2.判断有效个数✍3.维护窗口✍4.出窗口 💥5.完整代码 📃1.题目 力扣链接: 串联所有单词的子串 📜2.分析题目 阅…

口腔管理平台 |基于springboot框架+ Mysql+Java+B/S结构的口腔管理平台 设计与实现(可运行源码+数据库+lw文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 前台功能效果图 管理员功能登录前台功能效果图 会员功能 系统功能设计 数据库E-R图设计 lunwen参考…

智慧公厕建设的主要目标是什么?

随着城市化进程的不断推进,公共厕所作为城市基础设施的重要组成部分,也变得越来越重要。为了提升公共厕所的管理水平、提供更好的服务质量,智慧公厕应运而生。智慧公厕的建设旨在通过信息化手段实现公共厕所的全面感知监测,实现公…

remix Gas estimation failed,Remix中合约编译后的ABI以及bytecode位置,Remix中合约编译后的怎么测试

目录 remix Gas estimation failed Remix中合约编译后的ABI以及bytecode位置 Remix中合约编译后的怎么测试 remix Gas estimation failed 很有可能是你的solidity版本问题,重新复制我下编的,进行部署;

【Linux笔记-使用指南-备忘录】

虚拟机使用指南 创建虚拟机Linux使用指南yumJDKDockerLinux常用指令 RedisRedis配置key相关指令String相关指令待续... 创建虚拟机 点击我创建虚拟机 Linux使用指南 yum # 更新yum包 sudo yum update -y# 加入安装过旧版本,先卸载旧版本 sudo yum remove docker…

redis的基本知识点

连接Redis 在进行Redis操作之前&#xff0c;首先需要连接到Redis服务器。这可以通过使用redis-cli命令实现&#xff0c;具体命令格式如下&#xff1a; redis-cli -h <host> -p <port>其中&#xff0c;是Redis服务器的主机名或IP地址&#xff0c;是Redis服务器的端…

C语言自定义数据类型:用typedef声明新类型名

参考原文链接&#xff1a;https://blog.csdn.net/qq_57342311/article/details/129616215 除了可以直接使用 C 提供的标准类型名(如 int&#xff0c;char&#xff0c;float, double 和 long 等)和程序编写者自己声明的结构体、共用体、枚举类型外&#xff0c;还可以用 typedef …

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:FormLink)

提供静态卡片交互组件&#xff0c;用于静态卡片内部和提供方应用间的交互&#xff0c;当前支持router、message和call三种类型的事件。 说明&#xff1a; 该组件从API Version 10开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 该组件仅可…

6.【Linux】进程间通信(管道命名管道||简易进程池||简易客户端服务端通信)

介绍 进程间通信的方式 1.Linux原生支持的管道----匿名和命名管道 2.System V-----共享内存、消息队列、信号量 3.Posix------多线程、网路通信 进程间通信目的 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程 资源共享&#xff1a;多个进程之间共享同样的资源。…

Android存储概念及路径解析

Android存储概念及路径解析 在Android开发领域&#xff0c;理解不同的存储类型及其对应的文件系统路径对于设计和实现应用至关重要。本文将深入探讨内部存储、外部存储、内存和缓存的概念&#xff0c;并阐明storage/sdcard与mnt/sdcard的区别&#xff0c;以及/storage/emulate…