目录

  • 如何保证缓存与数据库的双写一致性
    • 先更新数据库,后更新缓存(不建议采用)
      • 原因一(会产生缓存与数据库数据不一致):在==高并发==的场景下,如果同时有请求 `A` 和请求 `B` 进行获取数据,那么会出现
      • 原因二(业务场景角度)
    • 先更新缓存,后更新数据库(不建议采用)
    • 先删除缓存,后更新数据库(不太理想,可以采用)
      • 解决方案
        • 为什么要休眠 `1` 秒钟,还要再次删除缓存
        • 那么这个 `1` 秒钟是怎么确定的
        • 那么采用延时双删策略,如第二次删除缓存失败怎么办
    • 先更新数据库,后删除缓存(==建议采用==)
      • 那么采用==延时双删策略==时,如第二次删除缓存失败怎么办
        • 方案一
        • 方案二

如何保证缓存与数据库的双写一致性

只要使用到缓存,无论是本地内存做缓存还是使用 redis 做缓存,那么就会存在缓存与数据库同步的问题,接下来就讨论一下关于保证缓存和数据库双写时的数据一致性

我们这里列出来所有策略,并且讨论他们优劣性

  • 先更新数据库,后更新缓存(不建议采用)
  • 先更新缓存,后更新数据库(不建议采用)
  • 先删除缓存,后更新数据库(不太理想,可以采用)
  • 先更新数据库,后删除缓存(建议采用)

先更新数据库,后更新缓存(不建议采用)

这套解决方案,大家普遍反对的,一般是没有人使用的

原因一(会产生缓存与数据库数据不一致):在高并发的场景下,如果同时有请求 A 和请求 B 进行获取数据,那么会出现

  • 请求 A 更新了数据库
  • 请求 B 也更新了数据库
  • 请求 B 更新了缓存
  • 请求 A 更新了缓存

这就出现了请求 A 更新缓存应该比请求 B 更新缓存早才对,但是因为网络等原因,B 却比 A 更早更新了缓存。这就导致了脏数据,因此不考虑

原因二(业务场景角度)

  • 如果你是一个写数据库场景比较多,而读数据场景比较少的业务需求,采用这种方案就会导致,数据压根还没读到,缓存就被频繁的更新,浪费性能
  • 如果你写入数据库的值,并不是直接写入缓存的,而是要经过一系列复杂的计算再写入缓存。那么,每次写入数据库后,都再次计算写入缓存的值,无疑是浪费性能的。显然,删除缓存更为适合

先更新缓存,后更新数据库(不建议采用)

这套解决方案,一般是没有人使用的。也会出现上述情况

先删除缓存,后更新数据库(不太理想,可以采用)

该方案会导致 “缓存与数据库的数据” 不一致,原因:在高并发的场景下,如果同时有一个请求 A 进行写数据操作,请求 B 进行读数据操作,那么会出现

  • 请求 A 开始进行写操作,删除缓存
  • 此时请求 B 开始进行读操作,发现缓存没有数据
  • 然后,请求 B 去数据库查询得到数据(得到的不是请求 A 写入的新数据,是旧数据,是脏数据)
  • 请求 B 将拿到的数据写入缓存
  • 此时,请求 A 才正式进行写操作

注意:在高并发的场景下,如果同时有一个请求 A 和请求 B 都进行写数据操作,那么是不会出现缓存与数据库数据不一致的情况的

解决方案

可以采用延时双删策略,伪代码如下

public void write(String key, Object data) {// 删除缓存 redis.delKey(key);// 再写数据库 db.updateData(data);// 线程休眠 1 秒钟 Thread.sleep(1000);// 再次删除缓存redis.delKey(key);
}

为什么要休眠 1 秒钟,还要再次删除缓存

这样可以使得请求 A 在写完数据时,可以将请求 B 写入缓存的脏数据删除掉

那么这个 1 秒钟是怎么确定的

针对上面的情形,读者应该自行评估自己的项目的读数据业务逻辑的耗时,然后写数据的休眠时间则在读数据业务逻辑的耗时基础上,加几百 ms 即可。这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据

那么采用延时双删策略,如第二次删除缓存失败怎么办

具体解决方案,且看第四种的策略的解析

先更新数据库,后删除缓存(建议采用)

对于这种方案,在 《Cache-Aside pattern》 有提到,另外,知名社交网站 facebook 也在论文 《Scaling Memcache at Facebook》 中提出,他们用的也是先更新数据库,再删缓存的策略

那么采用延时双删策略时,如第二次删除缓存失败怎么办

提供一个保障的重试机制即可,这里给出两套方案

方案一

  • 更新数据库数据
  • 缓存因为种种问题删除失败
  • 将需要删除的 key 发送至 MQ 消息队列
  • 自己消费消息,获得需要删除的 key
  • 继续重试删除操作,直到成功

然而,该方案有一个缺点,对业务线代码造成大量的侵入。于是有了方案二,在方案二中,启动一个订阅程序去订阅数据库的 binlog,获得需要操作的数据。在应用程序中,另起一段程序,获得这个订阅程序传来的信息,进行删除缓存操作

方案二

  • 更新数据库数据
  • 数据库会将操作信息写入 binlog 日志当中
  • 订阅程序提取出所需要的数据以及 key
  • 另起一段非业务代码,获得该信息
  • 尝试删除缓存操作,发现删除失败
  • 将这些信息发送至消息队列
  • 重新从消息队列中获得该数据,重试操作

备注说明:上述的订阅 binlog 程序在 mysql 中有现成的中间件叫 canal,可以完成订阅 binlog 日志的功能。如果对一致性要求不是很高,直接在程序中另起一个线程,每隔一段时间去重试即可,这些大家可以灵活自由发挥,只是提供一个思路

如何保证缓存与数据库的双写一致性相关推荐

  1. Redis面试 - 如何保证缓存与数据库的双写一致性?

    Redis面试 - 如何保证缓存与数据库的双写一致性? 面试题 如何保证缓存与数据库的双写一致性? 面试官心理分析 你只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致 ...

  2. 面试:高频面试题:如何保证缓存与数据库的双写一致性?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 来源 | blog.csdn.net/chang384915878 ...

  3. 面试必问:怎么保证缓存与数据库的双写一致性?

    点击蓝色"程序猿DD"关注我 回复"资源"获取独家整理的学习资料! 来源:https://dwz.cn/5AlJ2nWV 只要用缓存,就可能会涉及到缓存与数据库 ...

  4. 高频面试题:如何保证缓存与数据库的双写一致性?

    分布式缓存是现在很多分布式应用中必不可少的组件,但是用到了分布式缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题? Cache Aside ...

  5. 一个经典面试题:如何保证缓存与数据库的双写一致性?

    作者:你是我的海啸 地址:https://blog.csdn.net/chang384915878/article/details/8675646 只要用缓存,就可能会涉及到缓存与数据库双存储双写,你 ...

  6. 阿里MySQL读写一致_阿里面试题:如何保证缓存与数据库的双写一致性?

    作者:你是我的海啸 出处:https://blog.csdn.net/chang384915878/article/details/86756463 只要用缓存,就可能会涉及到缓存与数据库双存储双写, ...

  7. 读数据库遇到空就进行不下去_如何保证缓存与数据库的双写一致性?

    作者:你是我的海啸 来源:https://blog.csdn.net/chang384915878 分布式缓存是现在很多分布式应用中必不可少的组件,但是用到了分布式缓存,就可能会涉及到缓存与数据库双存 ...

  8. 经典面试题:如何保证缓存与数据库的双写一致性?

    作者:你是我的海啸 地址:http://t.cn/EK64FeP 只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题? 面试题剖析 一 ...

  9. 灵魂拷问:缓存与数据库的双写一致性如何保证?

    原文:https://blog.csdn.net/chang384915878/article/details/86756463 转载自技术联盟之巅 分布式缓存是现在很多分布式应用中必不可少的组件,但 ...

  10. 如何保证缓存和数据库的双写的一致性

    最初级的缓存不一致问题以及解决方案 问题: 先修改数据库,再删除缓存,如果删除缓存失败了,那么会导致数据库中是新数据,缓存中是旧数据,数据出现不一致 解决思路: 先删除缓存:再修改数据库,如果删除缓存 ...

最新文章

  1. 【控制】第九章-线性系统的状态空间描述
  2. P2580-于是他错误的点名开始了【Trie,字符串】
  3. stl之截取:以一段字符串截取字符串
  4. Semaphore1.8源码
  5. 原声php 读取excel乱码_如何解决php读取excel乱码问题
  6. 关于debian网卡驱动
  7. godot正确设置2d像素游戏
  8. 联想服务器怎么拆硬盘,联想ThinkStation P900工作站高清拆解
  9. dsp6657的helloworld例程测试-第一篇
  10. wind 10 安装node环境
  11. 厦门情侣必去浪漫的餐厅
  12. 计算机视觉(北邮鲁鹏)--卷积
  13. 粽子大战 —— 猜猜谁能赢
  14. 小程序swiper切换闪屏问题
  15. RxJava之过滤操作符
  16. 石家庄市学府路机动车科目三考场路线详细教案
  17. 【npm 报错 gyp info it worked if it ends with ok 大概率是包版本问题】
  18. 案例分享 | TensorFlow 在贝壳找房中的实践
  19. day007-列表和字典
  20. 基于H5 小程序 UI框架选型 2020年9月10号

热门文章

  1. 自动驾驶 2-1 第 1 课补充阅读:传感器和计算硬件 -- 上
  2. 2021-08-26BERT: Pre-training of Deep Bidirectional Transformers forLanguage Understanding
  3. N!阶层末尾有多少0
  4. Optional Interview with Benny the Irish Polyglot abo---coursera课程Learn how to learn
  5. pyqt5 窗口设置圆角_pyqt5-30. QWidget设置圆角,使用qss设置失败
  6. linux拷贝文件后几百行,我 的 一 些 练 习 题
  7. python编程符号大全_2020 年最值得学习的 5 大 AI 编程语言
  8. python的规模有多大_Python项目可以有多大?最多可以有多少行代码?
  9. 常问的数据结构与算法
  10. SSRF 服务器端请求伪造