一、Redis 数据一致性问题产生的原因

对 Redis和数据库的操作有 2 种方案:
1、先操作(删除) Redis,再操作数据库
2、先操作数据库,再操作(删除) Redis
上述二种方案,都希望数据操作要么都成功,要么都失败,也就是最好是一个原子操作,我们不希望看到一个失败,一个成功的结果,因为这样就产生了数据不一致的问题。
举例说明
假设 Redis 里缓存了一个热点商品数据,有个 key 为 1 的商品名称为“衣服”,数据库里这个 1号的商品名称也是衣服;此时商家觉得商品名称叫衣服有点宽泛,需要精确一下,把 1 号商品的名称修改为其对应的具体名称“短袖”。
1、如果我们选择先操作 Redis,再操作数据库的方案,当操作 Redis 成功,操作数据库失败的时候,Redis 里的名称修改为“短袖”,但是数据库的名称还是“衣服”,产生了数据不一致问题。
2、如果我们选择先操作数据库,再操作 Redis 的方案,当操作数据库成功,操作 Redis 失败的时候,数据库里的名称修改为“短袖”,但是 Redis 的名称还是“衣服”,产生了数据不一致问题。

二、解决方案

因为数据库是稳定的持久化的系统,比 Redis可靠,我们一般都是以数据库的数据为准,解决这个数据一致性问题的原则就是:我们可以为 Redis 缓存数据设置一个过期的时间,当 Redis 数据过期了就去数据库查询,然后再把数据库的数据写入 Redis 缓存中,确保数据的一致性。
如果在这个过期时间范围内,数据发生了更新操作,当更新操作有一个失败,有一个成功,就会产生不一致的问题,这个过期时间设置的太短了,数据库的压力还是很大,过期时间设置的太长了,不一致性的问题就会凸显,因此我们需要基于以数据库的数据为准的原则下,解决一致性问题。

1.Redis 更新方案

使用场景:更新代价小,数据不会牵扯到多个接口,没有出现大型的数据,只是简单的更新,更新的数据直接可以获取到!

(1)先更新 Redis,再更新数据库

首先不推荐选择这种方案。因为我们的数据一致性的基本原则是以数据库的数据为准,所以先更新缓存的话,会存在缓存更新成功,数据库更新失败的情况,此时面临的问题就需要回滚掉刚才更新缓存成功的操作,那么就需要从业务代码里加入很多判断逻辑来处理这种异常,需要考虑数据变化是 insert,update,delete 等,根据不同的场景执行不同的回滚方案,这种回滚操作比较麻烦,对我们业务代码的倾入性也比较大,所以不推荐选择这种方案。当然,如果业务层面可以接受这种数据的不一致性,异常情况就不需要考虑,选择这种方案也是可以的。

(2) 先更新数据库,再更新 Redis

先更新数据库,再更新 Redis 的方案,由于把数据库操作放到了前面,如果数据库操作失败,那么客户端再发起一次就可以了。如果数据库操作成功,Redis 操作失败,此时由于数据库的数据已经设置成功,我们的重点就是讨论如何把 Redis的数据操作成功即可。从客户端层面来看,他提交的数据已经在我们系统里存在了,此时的问题就是我们系统内部如何解决的问题。对于 Redis 操作失败,我们可选的方案有以下几个,根据业务要求的数据一致性级别,进行权衡选择即可。
1、如果数据一致性要求不是很高,不做任何操作,等着Redis里的缓存数据过期后,自动从数据库同步最新的数据,此时最严重的数据不一致性周期就是在缓存过期的一段时间(考虑一下这个过期时间的范围);如果在这个时间段内,又有新的更新请求,也许这次就更新缓存成功了。
2、如果数据一致性要求比较高,那么 Redis 操作失败后,我们把这个操作记录下来,异步处理,用 Redis 的数据去和数据库比对,如果不一致,再次更新缓存确保缓存数据与数据库数据一致。

2.选择 Redis 删除方案(主流)

应用场景:拿到数据更新到 Redis 需要经过很多表的关联查询,或者多个接口的调用查询,经过大量计算才能得到数据的话,就不要使用更新 Redis 的方案了,因为面对这种复杂的更新流程,可以直接删掉方便。

(1)先更新数据库,再删除 Redis

我们如果更新数据库成功,删除 Redis 失败,那么 Redis 里存放的就是一个旧值,也就是删除缓存失败导致缓存和数据库的数据不一致了。对于删除 Redis 失败的异常情况来进行分析,我们一般有如下的方案:
1、我们可以重试删除,比如:我们可以把删除动作发送到消息队列 MQ,MQ的消费者再去删除这个key,一致尝试删除操作,确保缓存删除成功,这个方案缺陷就是删除缓存的地方,通过代码实现对业务逻辑产生了入侵。
2、另外一种方案,就是完全异步的方案,对业务逻辑没有入侵,通过监听 binlog 的变化来删除缓存。我们更新数据库会产生 binlog,我们可以用一个服务监听数据库 binlog 的变化,异步去删除缓存,阿里开源的 canal 就是可以监听 binlog 的工具,只要数据发生变化就可以删除 Redis 的数据。

(2)先删除 Redis,再更新数据库

并发下可能产生数据一致性问题
举例

上面的图表示,Thread-1 是个更新流程,Thread-2 是个查询流程,cpu 执行顺序是:Thread-1 删除缓存成功,此时 Thread-2 获取到 CPU 执行查询缓存没有数据,然后查询数据库把数据库的值写入缓存,因为此时 Thread-1 更新数据库还没有执行,所以缓存里的值是一个旧值(old),最后 CPU 执行 Thread-1 更新数据库成功的代码,那么此时数据库的值是新增(new),这样就产生了数据不一致行的问题。
解决上述问题的两种方案:
(1)加锁,使线程顺序执行:如果一个服务部署到了多个机器,就变成了分布式锁,或者是分布式队列按顺序去操作数据库或者 Redis,带来的副作用就是:数据库本来是并发的,现在变成串行的了,加锁或者排队执行的方案降低了系统性能,所以这个方案看起来不太可行。
(2)采用双删:先删除缓存,再更新数据库,当更新数据后休眠一段时间再删除一次缓存。
伪代码:

redes.del(key);
db.update(data);
Thread.sleep(2000);
redes.del(key);

Redis与数据库缓存一致性问题相关推荐

  1. 两次被裁之后,我终于解决了数据库缓存一致性问题

    一 我是一名毕业两年的程序员. 算上实习,工作三年了,正是一个程序员的黄金时代,这让我普通而自信. 但是从实习期,我就被辞退两次了. 今天是我的又一场面试,而且是大厂面试.我要一洗前耻,证明自己. 好 ...

  2. redis和数据库的一致性问题的解决方案

    当前没有框架能够保证redis的数据和数据库的完全一致性,所以需要 我们自己在性能和一致性上作取舍. 使用到缓存的场景 这里讲到的是缓存和数据库的一致性问题.当查询数据库数据的时候,才涉及到缓存的利用 ...

  3. 使用Redis进行数据库缓存

    当我们网站的数据量过大时,使用Java频繁访问数据库会造成延迟过大.数据丢失等问题,这时候就需要使用缓存技术将经常访问的数据保存在缓存数据库以减少数据库访问.我们经常使用Redis作为缓存数据库. 当 ...

  4. 面试老大难的数据库缓存一致性问题

    在数据库和缓存的操作过程中,可能存在"先写数据库,后删缓存"."先写数据库,后更新缓存"."先删缓存库,后写数据库"以及"先更新缓 ...

  5. 再有人问你数据库缓存一致性的问题,直接把这篇文章发给他

    在之前的一篇文章<为什么会出现数据库和缓存不一致的问题>中,我们介绍过缓存和数据库会出现数据不一致的几种情况. 我们提到过,在数据库和缓存的操作过程中,可能存在"先写数据库,后删 ...

  6. 数据库缓存一致性问题

    在数据库和缓存的操作过程中,可能存在"先写数据库,后删缓存"."先写数据库,后更新缓存"."先删缓存库,后写数据库"以及"先更新缓 ...

  7. redis 数据库 缓存一致性

    1.常用的缓存图如下: 高频查找某数据时,可以考虑使用redis缓存.当查找时,首先从redis中查找,如果已存在就直接从redis读取返回,如果redis中不存在,就从数据库中查找,再写入Redis ...

  8. docker 安装mysql、canal、redis实现redis和mysql缓存一致性

    一.canal介绍 Canal 是用 Java 开发的基于数据库增量日志解析,提供增量数据订阅&消费的中间件. 目前,Canal 主要支持了 MySQL 的 Binlog 解析,解析完成后才利 ...

  9. 如何保证Redis和数据库的一致性

    在使用Redis中,我们都会遇到同样的问题,当一个请求要更新数据库时,Redis缓存显然也要被更新.我们必须要保证两者的一致性. 而数据库和Redis是两个不同的进程,很难保证两个进程更新都一定能完成 ...

最新文章

  1. PCA和白化练习之处理图像
  2. crackme算法分析---CRC32算法的妙用
  3. 闵可夫斯基和(Mincowsky sum)
  4. 突破极限–如何使用AeroGear Unified Push for Java EE和Node.js
  5. xcode扩展_如何将Xcode插件转换为Xcode扩展名
  6. gitlab搭建与使用
  7. 为什么以太网中需要 最小帧
  8. 数据库练习题总题库选择判断简答操作题
  9. 创世纪游戏、黄金分割比
  10. 回忆大学到现在为止学到了什么?
  11. 全球首个航天大模型问世,文心秒补《富春山居图》,这是百度普惠AI的恒心...
  12. DELL戴尔开启/关闭触摸板方法
  13. 安卓psp模拟器联机教程_psp模拟器联机游戏下载-psp模拟器联机对战版v1.0 安卓版 - 极光下载站...
  14. 今天开始开发竞争情报系统了,在这里做个记录
  15. WinDjView对AfxMessageBox的定制
  16. 解决mac休眠睡眠异常耗电方法
  17. 关于offer、三方协议、福利等就业常识
  18. IE浏览器连不上网电脑无法联网
  19. C语言去除图像的离散区域,Visual C++数字图像实用工程案例精选
  20. Android App屏幕旋转要点

热门文章

  1. Scrapy 调用chrome浏览器的middleware
  2. Python生成(x,y,z)三维坐标序列
  3. 5元以下纯铜小摆件_【拍4斤发5斤】早餐饼干网红早餐代餐曲奇酥性小饼干零食500g6元优惠券券后价5.8元...
  4. android 蒙版图片带拖动_黑橙修图:新手入门篇2-一句话带你认识图层蒙版
  5. rsync实时同步服务部署
  6. NOIP2016-D2-T2 蚯蚓(单调队列)
  7. 16、React Native实战之TextInput组件
  8. Win7下DB2 Express-C 9.7.2的卸载与安装(上)
  9. 一步一步教你使用AgileEAS.NET基础类库进行应用开发-系列目录
  10. python去掉数字列表中括号_如何从列表中的元素中移除括号(Python)