一般来说,只要你用到了缓存,不管是Redis还是memcache,就可能会涉及到数据库缓存与数据的一致性问题,这里我们以Redis为例。

我们该如何保证Redis与数据库的一致性呢?

So easy:

更新的时候,先更新数据库,然后再删除缓存。
读的时候,先读缓存;如果没有的话,就读数据库,同时将数据放入缓存,并返回响应。
乍一看,一致性问题貌似很好的得到了解决。但仔细一想,你会发现还是有问题:如果先更新了数据库,删除缓存的时候失败了怎么办?那么数据库中是新数据,缓存中是老数据,数据出现不一致了。

改进方案:

先删除缓存,后更新数据库。因为即使后面更新数据库失败了,缓存是空的,读的时候会从数据库中重新拉,虽然都是旧数据,但数据是一致的。

所以方案就变成了:

更新的时候,先删除缓存,然后再更新数据库。
读的时候,先读缓存;如果没有的话,就读数据库,同时将数据放入缓存,并返回响应。

到这里是不是问题就得到了彻底的解决了呢?其实并没有,在高并发的场景下,会出现这样的情况:数据发生了变更,先删除了缓存,然后去修改数据库。此时还没来得及修改,一个请求过来了,去读缓存,发现缓存空了,去读数据库,读到了准备修改前的旧数据,并且把旧数据放到了缓存。随后,数据变更程序完成了数据库的修改。那么完了,这个时候发生数据不一致了......

解决方案:

针对这种情况,可以先把“修改DB”的操作放到一个JVM队列,后面读请求过来之后,“更新缓存”的操作也放进同一个JVM队列,每个队列,对于一个作业线程,按照队列的顺序,依次执行相关操作,这样就可以保证“更新缓存”一定是在DB修改之后,以保证数据一致性,具体如下图所示:

细想该方案,其实还有几个优化点

1、读请求过多的时候,队列里面会有多个“更新缓存”操作串在一起,其实是没有意义的,往队列里面塞数据的时候可以先判断一下,有的话就不用再塞进去了

2、遇到更新DB比较频繁的业务场景时,可能会导致读请求长时间阻塞,这个时候可以通过扩机器增加吞吐量,或者可以先返回一个旧的值。

如何保证Redis与数据库的数据一致性的更多相关文章

  1. Redis和数据库的数据一致性问题

    在数据读多写少的情况下作为缓存来使用,恐怕是Redis使用最普遍的场景了.当使用Redis作为缓存的时候,一般流程是这样的. 如果缓存在Redis中存在,即缓存命中,则直接返回数据 如果Redis中没 ...

  2. NOSQL中的redis缓存数据库

    NOSQL概述 什么是NOSQL? NoSql(NoSQL=Not Only SQL),意思为"不仅仅是SQL",是一个全新的数据库理念,泛指非关系型的数据库. 为什么需要NOSQ ...

  3. Redis 当成数据库在使用和可靠的分布式锁,Redlock 真的可行么?

    怎样做可靠的分布式锁,Redlock 真的可行么? https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html ...

  4. Redis和数据库 数据同步问题

    Redis和数据库同步问题 缓存充当数据库 比如说Session这种访问非常频繁的数据,就适合采用这种方案:当然了,既然没有涉及到数据库,那么也就不会存在一致性问题: 缓存充当数据库热点缓存 读操作 ...

  5. 高并发架构系列:Redis缓存和MySQL数据一致性方案详解

    一.需求起因 在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节.所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问MySQL等数据库. 这个业务场景, ...

  6. Redis缓存和MySQL数据一致性方案(转)

    需求起因 在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节.所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问MySQL等数据库. 这个业务场景,主要 ...

  7. 怎么保证 redis 和 db 中的数据一致

    你只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题? 首先需要考虑到:更新数据库或者更新缓存都有可能失败,在这种前提下分析业务带来的 ...

  8. Redis与DB的数据一致性解决方案(史上最全)

    文章很长,而且持续更新,建议收藏起来,慢慢读! 高并发 发烧友社群:疯狂创客圈(总入口) 奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : 极致经典 + 社群大片好评 < Java 高并发 三 ...

  9. Redis缓存数据库的安装与配置(3)

    3 Redis主动同步设置方法 Redis主从同步 1.Redis主从同步特点 一个master可以拥有多个slave 多个slave可以连接同一个master,还可以连接到其他slave 主从复制不 ...

随机推荐

  1. JS中数组的拷贝方法

    之前在写一个vue的计算属性时,大概是这样: computed: { updateList () { let newList = this.List /*do something*/ return n ...

  2. jmeter之报告输出(html)

    在使用jmeter进行测试时,我们需要生成相应的测试报告,jmeter3.0之后有自带的测试报告. 在测试报告的格式和输出内容不满足需求时,我们可以根据需要去修改其配置文件(jmeter.proper ...

  3. Git配置用户名、邮箱

    当安装完 Git 应该做的第一件事就是设置你的用户名称与邮件地址. 这样做很重要,因为每一个 Git 的提交都会使用这些信息,并且它会写入到你的每一次提交中,不可更改. 否则,用户名会显示为unkno ...

  4. vimiumC的下载、配置与节点个性化

    vimium是chrome的一款扩展程序,正如其名:vim+chromium,它能让你在浏览网页时双手不离开键盘,是提上网高效率的神器. 最近在使用中,非常便捷高效,但关于节点的个性化资料比较少,自己 ...

  5. 03Java面试题-------------中科软

    1.String是最基本的数据类型吗?String和StringBuffer的区别? 不是.Java中的基本数据类型只有8个:byte,short,int,long,float,double,char ...

  6. 20191110 Spring Boot官方文档学习(3)

    3.使用Spring Boot 3.1.构建系统 建议选择Maven或Gradle作为构建工具 每个Spring Boot版本都提供了它所支持的依赖关系的精选列表.实际上,您不需要为构建配置中的所有这 ...

  7. (已实践)PLSQL本地还原Oracle数据库dmp文件

    这个方法很烂,导致重装Oracle时候处处出现问题,不建议使用这个方法,除非你以后不再用Oracle这个软件了,这个方法很烂,再评论一下. 第一,启动服务,(如果数据库处于启动状态,那么略过这一步) ...

  8. 堆排序 && Kth Largest Element in an Array

    堆排序 堆节点的访问 通常堆是通过一维数组来实现的.在数组起始位置为0的情形中: 父节点i的左子节点在位置(2*i+1); 父节点i的右子节点在位置(2*i+2); 子节点i的父节点在位置floor( ...

  9. QQ管理

    ##用例1:查询数据 #01.查询QQ号码为54789625的所有好友信息,包括QQ号码,昵称,年龄 # # SELECT `relation`.RelationQQID AS QQ号码,`basei ...

  10. 图——图的Prim法最小生成树实现

    1,运营商的挑战: 1,在下图标出的城市间架设一条通信线路: 2,要求: 1,任意两个城市间都能够通信: 2,将架设成本降至最低: 2,问题抽象: 1,如何在图中选择 n - 1 条边使得 n 个顶点 ...