如何保证Redis缓存和数据库的一致性问题

熟练掌握Redis缓存技术?

那么请问Redis缓存中有几种读写策略,又是如何保证与数据库的一致性问题

今天来聊一聊常用的三种缓存读写策略

首先我们来思考一个问题

服务端到底是先更新db还是先更新cache

如果先更新缓存

  • 先更新缓存
  • 再更新数据库

首先如果缓存更新成功但数据库更新失败,会导致数据不一致的问题

其次当请求A发起写请求,先更新缓存,于此同时请求B发起读请求,返回数据后,数据库被更新,照成了数据不一致的情况

这种概率大吗?

大,因为redis操作比数据库操作快的多,很容易发生

redis为什么那么快?

第一,Redis 的大部分操作在内存上完成,内存操作本身就特别快;

第二,Redis追求极致,选择了很多高效的数据结构,并做了非常多的优化,比如 hash,跳表,有时候一种对象底层有几种实现以应对不同场景。

第三,Redis 采用了多路复用机制,使其在网络 IO 操作中能并发处理大量的客户端请求,IO 多路复用机制是指一个线程处理多个 IO 流,就是我们经常听到的 select/epoll 机制。简单来说,在 Redis 只运行单线程的情况下,该机制允许内核中,同时存在多个监听 Socket 和已连接 Socket。内核会一直监听这些 Socket 上的连接请求或数据请求。一旦有请求到达,就会交给 Redis 线程处理,这就实现了一个 Redis 线程处理多个 IO 流的效果。

如果先更新数据库

写 

  • 先更新数据库
  • 再更新缓存

请求A发起写请求,将数据库更新成功,于此同时请求B发起写请求,在A成功修改数据库后也将数据库更新成功,并在请求A之前更新缓存,随后请求A更新缓存

数据库的数据是第二次更新操作的数据,而缓存确还是第一次更新操作的数据,也就是出现了数据库和缓存的数据不一致的问题

都不对,选择删除缓存

不更新缓存,而是删除缓存中的数据。然后,到读取数据时,发现缓存中没了数据之后,再从数据库中读取数据,更新到缓存中,那么到底是先删除缓存,还是先更新数据库呢

如果先删除缓存

假设请求A发起写请求,于是他先删除缓存,于此同时请求B发起读请求,缓存未击中,那么查询数据库,查询成功后将数据写入缓存中,随后请求A修改数据库

数据发生了不一致

如果先更新数据库

假设请求A发起读请求,请求未命中缓存,查询数据库,在未写入缓存时有个请求B发起写请求,修改数据库后删除缓存,随后请求A写入缓存

数据发生了不一致

但我们之前说过,redis的速度快于数据库,几乎不可能发生这种情况

所以最后选择先更新数据库,而这种思想正是我们的Cache Aside

Cache Aside Pattern

Cache Aside Pattern 是我们平时使用比较多的一个缓存读写模式,比较适合读请求比较多的场景,服务端需要同时维系 db 和 cache,并且是以 db 的结果为准

  •  查询缓存,缓存中查询到了直接返回
  • 查询不到时查询数据库,
  • 查询完数据库后将数据更新至缓存

  •    修改数据库
  •    删除缓存

那么能不能先删除缓存再更新数据库呢?

答案是 不能,这样会导致数据的不一致性

当请求A 发起写请求,此时删除缓存,同时请求B发起读请求,由于没有缓存查询数据库,随后请求A更新数据库

通常情况下,查询数据库的速度比修改数据库更快。这是因为查询操作通常只涉及对数据库中的数据进行读取和匹配,并且可以使用合适的索引来加速查询过程。相比之下,修改操作需要对数据库中的数据进行写入和更新,可能还需要触发额外的数据库约束、触发器或日志记录等操作,这些都会增加一定的开销和时间。

那么是不是先更新数据库再删除缓存是不是就没有数据不一致的情况呢? 

答案是 并不是

当请求A发起读请求,恰巧此时缓存过期,需要查询数据库,此时请求B发起写请求,由于没有缓存,故不会执行删除缓存操作,请求A查询完数据库将数据写入缓存,请求B随后更新数据库

但因为要同时达成读缓存时缓存失效并且有并发写的操作,而操作缓存比操作数据库要快得多,所以概率要小很多

那么如何解决这种情况呢?

更新完数据后的时候同时更新缓存,并且我们需要加一个锁/分布式锁来保证更新 cache 的时候不存在线程安全问题,确保数据库和缓存的强一致问题

那么对于首次请求一定不存在cache的情况如何解决呢?

可以设置定时任务将热点数据提前放入 cache 中

Read/Write Through​

原理:Read/Write Through原理是把更新数据库的操作由缓存代理,cache 服务负责将此数据读取和写入 db,从而减轻了应用程序的职责。
Read Through:如果命中缓存则直接返回数据,如果没有命中则查询数据库,随后写入到缓存中并返回
Write Through:当有数据更新的时候,如果没有命中缓存,直接更新数据库,然后返回。如果命中了缓存,则更新缓存,然后再由缓存自己更新数据库(这是一个同步操作)。

Write Behind​

原理:在更新数据的时候,只更新缓存,不更新数据库,而缓存会异步地批量更新数据库。这个设计的好处就是让数据的I/O操作非常快,带来的问题是,数据不是强一致性的,而且可能会丢。​
对比Read/Write Through 是同步更新 cache 和 db,而 Write Behind 则是只更新缓存,不直接更新 db,而是改为异步批量的方式来更新 db

非常适合一些数据经常变化又对数据一致性要求没那么高的场景,比如浏览量、点赞量

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

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

相关文章

篇二:工厂方法模式:灵活创建对象

篇二:“工厂方法模式:灵活创建对象” 开始本篇文章之前先推荐一个好用的学习工具,AIRIght,借助于AI助手工具,学习事半功倍。欢迎访问:http://airight.fun/。 另外有2本不错的关于设计模式的资料&#xff…

Lombok 的安装与使用

文章目录 一、什么是 Lombok1.1 Lombok 的概念1.2 为什么使用 Lombok1.3 Lombok 的相关注解 二、Lombok 的安装2.1 引入依赖2.2 安装插件 三、Lombok 的使用案例四、Lombok 的原理 一、什么是 Lombok 1.1 Lombok 的概念 Lombok(“Project Lombok”)是一…

MySQL 窗口函数

聚合函数作为窗口函数 设聚合函数为op语法结构: op(字段名A) over(partition by 字段名B order by 字段名C rows between D1 and D2) 其中: partition by:按照某一字段将数据进行分组 order by:按照某一字段将数据进行排序&…

Java实现八皇后问题

八皇后问题说明 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯贝瑟尔于 1848 年提出:在 88 格的国际象棋上摆放八个皇后,使其不能互相攻击,即:任意两个皇后都不…

HTTP常用状态码及其含义

HTTP常用状态码及其含义 1XX:信息,服务器收到请求,需要请求者继续执行操 状态码状态码英文名称中文描述100Continue继续。客户端应继续其请求101Switching Protocols切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议&…

筛选给定范围内的日志

目录 1.时间戳 2.实例 1.首先创建ubuntu.log日志 2.写dem.awk创建规则 3.筛选 1.时间戳 一个能表示一份数据在某个特定时间之前已经存在的、 完整的、 可验证的数据,通常是一个字符序列,唯一地标识某一刻的时间。 awk提供了mktime()函数,它可以将时间…

31 对集合中的字符串,按照长度降序排列

思路&#xff1a;使用集合的sort方法&#xff0c;新建一个Comparator接口&#xff0c;泛型是<String>&#xff0c;重写里面的compare方法。 package jiang.com; import java.util.Arrays; import java.util.Comparator; import java.util.List;public class Practice4 {…

Spring Security 和 Apache Shiro 登录安全架构选型

Spring Security和Apache Shiro都是广泛使用的Java安全框架&#xff0c;它们都提供了许多功能来保护应用程序的安全性&#xff0c;包括身份验证、授权、加密、会话管理等。 Spring Security和Apache Shiro都是非常常用的登录安全框架,两者在登录安全架构的选型上各有特点: Sp…

WSL 2 installation is incomplete的解决方案

问题描述 解决方案 在Windows功能中开启Hyper-v 如果没有Hyper-v选项&#xff0c;新建文本粘贴以下内容后以.cmd为后缀保存后执行即可 pushd "%~dp0" dir /b %SystemRoot%\servicing\Packages\*Hyper-V*.mum >hyper-v.txt for /f %%i in (findstr /i . hyper-v.t…

C语言进阶-3

1、程序为什么需要内存 1.1、计算机程序运行的目的 计算机为什么需要编程&#xff1f;编程已经编了很多年&#xff0c;已经写了很多程序&#xff0c;为什么还需要另外写程序&#xff1f;计算机有这个新的程序到底为了什么&#xff1f; 程序的目的是为了去运行&#xff0c;程序…

C++ 派生类的拷贝构造函数

当存在类的继承关系时&#xff0c;对于一个类&#xff0c;如果程序员没有编写拷贝构造函数&#xff0c;编译系统会在必要时自动生成一个隐含的拷贝构造函数&#xff0c;这个隐含的拷贝构造函数会自动调用基类的拷贝构造函数&#xff0c;然后对派生类新增的成员对象一一执行拷贝…

git merge 和rebase区别

Merge the incoming changes into the current branch 找到两个分支的祖先 commit&#xff0c;然后将公共分支最新版合并到自己的分支&#xff0c;形成一个新的 commit 提交&#xff0c;用图表示如下。 Rebase the current branch on top of the incoming Rebase 则是重新基于…

ubuntu samba 配置常见问题

samba配置&#xff1a; sudo vi /etc/samba/smb.conf [xxx 共享文件名] comment share folder browseable yes writable yes guest ok yes path /workdir/code/favarite create mask 0777 directory mask 0777 sudo /etc/init.d/smbd restart 重启smb服务 以上操作…

在服务器上搭建gitlab

最终效果展示&#xff1a; 官方文档&#xff1a; 安装部署GitLab服务 1.在服务器上下载gitlab wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7/gitlab-ce-12.9.0-ce.0.el7.x86_64.rpm rpm -ivh gitlab-ce-12.9.0-ce.0.el7.x86_64.rpm 2.编辑站点位置 vim …

Kotlin 1.9.0 发布:带来多项新特性,改进 Multiplatform/Native 支持

新特性 Kotlin 的最新版本引入了许多新的语言特性&#xff0c;包括用于开放范围的…<操作符、扩展正则表达式等。此外&#xff0c;它还改进了 Kotlin Multiplatform 和 Kotlin/Native 支持。 Kotlin 1.9 稳定了与枚举类关联的 entries 属性&#xff0c;它会返回所定义的枚…

Spring Boot Logback日志格式改为JSON

在阿里云、或者日志分析时使用JSON格式输出日志更加方便。 依赖 增加Logbak JSON解析依赖。 另外需要注意的是JSON格式输出依赖Jackson&#xff0c;根据工程情况按需添加Jackson依赖。 <!--日志--><dependency><groupId>ch.qos.logback.contrib</grou…

嵌入式软件C/C++(技术面试题)

一&#xff0c;网络 1&#xff0c;TCP窗口机制 TCP&#xff08;传输控制协议&#xff09;是一种可靠的、面向连接的传输层协议。其中的窗口机制是TCP协议中的一项重要功能&#xff0c;用于控制数据在发送和接收之间的流程。 TCP窗口机制是利用滑动窗口的方式来进行拥塞控制和…

基于Python的Locust 性能测试指北(万字长文详解)

目录 Locust 我们为什么选择locust Locust的核心部件 Locust内部运行调用链路 locust 实践 检查点&#xff08;断言&#xff09; 权重比例 参数化 Tag 集合点 分布式 docker 运行locust 高性能 FastHttpUser 测试gRPC等其他协议 其他 资料获取方法 Locust Locu…

Squeeze-and-Excitation Networks阅读笔记一

文章目录 Abstract1 INTRODUCTION Abstract 卷积算子&#xff08;convolution operator&#xff09;是卷积神经网络&#xff08;cnn&#xff09;的核心组成部分&#xff0c;它使网络能够通过融合每层局部接受域内的空间和通道信息来构建信息特征。广泛的先前研究已经调查了这种…

VC9、VC10、VC11等等各对应什么版本的Visual Studio,以及含义

文章目录 1、_MSC_VER 定义编译器的版本2、示例 1、_MSC_VER 定义编译器的版本 MS VC 15.0 _MSC_VER 1910 (Visual Studio 2017) MS VC 14.0 _MSC_VER 1900 (Visual Studio 2015) MS VC 12.0 _MSC_VER 1800 (VisualStudio 2013) MS VC 11.0 _MSC_VER 1700 (VisualStudio…