文章目录

  • 方案一:先更新数据库,再更新缓存
  • 方案二:先删除缓存,在更新数据库
  • 方案三:先更新数据库,再删除缓存
  • 双删方案的优化
  • 缓存删除失败怎么办?
  • 总结

首先要说明的是,接下来无论是哪种方案都只能保证最终一致,无法做到强一致性。

方案一:先更新数据库,再更新缓存

public void update() {updateDB();updateRedis();
}

异常场景:线程A比线程B先更新,但是由于网络等原因导致线程B先更新了缓存。然后A再把旧值更新到缓存中。这种异常场景除了设置过期时间,没有办法解决脏数据的问题。

从业务上考虑,如果你面对的是一个写多读少的场景,就会出现频繁更新缓存但是却没有人来读取的情况,浪费了性能。

其次,如果你用的缓存不是在简单的数据库值,而是那些要经过复杂计算才能得到缓存值的数据,这种方案无疑是很浪费的。

方案二:先删除缓存,在更新数据库

问题一:热点key的问题,如果是查询的热点key,很可能导致查询一下打到数据库了

解决方案:可以使用单机互斥锁来锁住它。其他的线程走到这一步拿不到锁就等着,等第一个线程查询到了数据,然后做缓存。后面的线程进来发现已经有缓存了,就直接走缓存。这样可以避免大量请求直接打到数据库。

问题二:数据不一致

当线程B删除缓存后导致缓存失效,此时线程A进来查询,查到了旧值,并将值写入到缓存中。然后线程B才更新数据库。这个方案导致脏数据和方案一中的类似,如果没有其它步骤只能依靠缓存过期的时间来解决了。

方案一,方案二中导致缓存不一致发生的情况类似。都需要再多一步来保证数据一致性。

解决方案:延时双删策略

public void write(String key,Object data){redis.delKey(key);db.updateData(data);Thread.sleep(1000);redis.delKey(key);}

就是再更新数据库后稍等一段时间再进行一次删除缓存的操作。

不过这个解决方案还有几个问题需要确认

  1. 删除应该休眠多久?

    线程B延迟的时间应该大于线程A再写入缓存时间的。

    需要测试项目中读取数据业务的耗时,写数据休眠的时间则再读取逻辑耗时加上百毫秒即可。这样就确保了读请求结束,写请求可以删除脏数据。

  2. 如果mysql主从读写分离又该休眠多久?

    如果有主从同步延时,休眠时间再加上主从延时的时间即可。

  3. 性能下降怎么解决?

    将删除的方案改为异步的方式。

方案三:先更新数据库,再删除缓存

方案三也就是我们的最终方案。这个也是facebook论文中提出的方案。下面是两篇论文有兴趣可以读一下。

https://docs.microsoft.com/en-us/azure/architecture/patterns/cache-aside
https://www.usenix.org/system/files/conference/nsdi13/nsdi13-final170_update.pdf

先来讨论下这总异常情况发生的条件,首先要查询的时候缓存失效,然后要求更新数据库要比查询先返回并成功删除掉缓存。这个概率可以说非常非常之小了。虽然概率比1号方案更小但仍然存在。

解决方案:采用方案二中的双删方案。

双删方案的优化

如果再业务代码中耦合了异步删除的逻辑,一个是代码复杂度变高,另一个是不够优雅。

幸好,阿里开源了一个中间件canal,它可以定义mysql的binlog,就可以根据binlog来做业务,比如更新缓存,发kafka等操作。

缓存删除失败怎么办?

经常再其他文章看见写所谓的因为删除缓存失败而选择某个方案的。我认为这是错误的。事实上,在这几个方案中都有删除失败的可能。如果要想确保一定不会失败,必须采用其他方案来保证。

总结

如果我们对数据的一致性要求没有那么高,直接使用方案三即可,这也是我们生产上最常使用的方案。如果要求较高,建议使用双删方案优化来确保数据库和缓存数据的最终一致性。

分布式系统中数据库与缓存一致性的几种方案的解析相关推荐

  1. 数据库缓存最终一致性的四种方案

    数据库缓存最终一致性的四种方案 背景 缓存是软件开发中一个非常有用的概念,数据库缓存更是在项目中必然会遇到的场景.而缓存一致性的保证,更是在面试中被反复问到,这里进行一下总结,针对不同的要求,选择恰到 ...

  2. 数据库与缓存一致性解决方案

    数据库与缓存一致性解决方案 文章目录 数据库与缓存一致性解决方案 前言 几种方案的分析 方案的实现 前言 项目中如果用到了缓存,就会涉及到数据库与缓存的双写,由于这两个操作不是原子性的,在并发的场景下 ...

  3. 数据库和缓存一致性的问题

    经常看到有人问怎么解决数据库和缓存一致性的问题,这个问题我觉得是不要去解决. 如果你不信你先看我列的几种情况 假设 数据库一开始和缓存都是1元. 用户更新数据库的同时双写缓存. 1.双写不删 写库充值 ...

  4. Web应用中避免Form重复提交的三种方案

    Web应用中避免Form重复提交的三种方案 2007-08-21 18:29 Web应用中重复提交的问题的三种解决方案 前两种是利用javascript,后面一种是在使用Struts的情况下的参考实现 ...

  5. 数据库和缓存一致性分析

    缓存由于其高并发和高性能的特性,已经在项目中被广泛使用,在读取缓存方面,大家没啥疑问,都是按照下图的流程来进行业务操作. 从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案.这种方案下,我们 ...

  6. 并发编程中的可见性——缓存一致性协议MESI

    一.应用场景展示--多线程计数 1.全局原子操作计数的数据流图 核心问题就是不同CPU如何在同一时刻看到同样的全局变量值. 2.每线程自增计数的数据流图 二.cache原理和实现 1. cache g ...

  7. linux中数据库的4种状态,数据库的数据持久有几种方案_数据库_数据管理_数据结构_课课家...

    容器中的数据可以存储在容器层.但是将数据存放在容器层存在以下问题: 数据不是持久化.意思是如果容器删除了,这些数据也就没了 主机上的其它进程不方便访问这些数据 对这些数据的I/O会经过存储驱动,然后到 ...

  8. 中的多行卡片如何居中_编程中如何让图片垂直居中?两种方案分享给大家

    flex方法 首先给图片添加一个div,设置其宽高及基本属性,其次把div中的display元素设置成flex,最后给img添加align-items:center属性,代码如下: Document ...

  9. android中MVC,MVP和MVVM三种模式详解析

    我们都知道,Android本身就采用了MVC模式,model层数据源层我们就不说了,至于view层即通过xml来体现,而 controller层的角色一般是由activity来担当的.虽然我们项目用到 ...

最新文章

  1. 如何打破30岁职业瓶颈?
  2. 电脑台式计算机描述不可用,win7系统计算机描述不可用的解决方法
  3. css text top,text-align属性(css中文本对齐属性)
  4. 56岁潘石屹下定决心学Python,60多岁程序语言之父们还在敲代码,你还敢懈怠吗?...
  5. c语言数据结构篇之栈(线性栈与链式栈)
  6. 【MFC】工具栏按钮单选效果
  7. php 数组 indexof,详解js中字符串和数组的indexof方法
  8. 软件压力测试报告要怎么写,如何做接口压力测试?压力测试报告应该包含哪些结果?...
  9. aida64使用教程
  10. 基于javaweb+jsp的小蜜蜂扩音器网上商城系统(java+JSP+Servlet+JDBC+Ajax+mysql)
  11. 【Python学习】sklearn层次聚类
  12. CTF-misc练习(https://buuoj.cn)之第二页
  13. 钉钉 服务器 消息推送,钉钉消息推送配置
  14. Arm 公司推出了 Mbed linux OS
  15. 【解决方案】EasyCVR安防视频云服务城市污水处理厂解决方案
  16. 鹿先森博客原先森博客(sey.ink)
  17. 【DG】基于同一个主机建立物理备库和逻辑备库 (三)
  18. java 重载条件
  19. 怎么用键盘快捷键将光标定位到浏览器地址栏
  20. qq批量登录软件_桔子引流系统qq引流,单人日产1000粉。

热门文章

  1. PLC编程序控制器的历史和展望
  2. mysql 修改自动递增值_MySql数据库自动递增值问题
  3. 王者荣耀手机助手服务器异常,如何解决王者荣耀助手登录网络异常
  4. 运营商大数据如何成为企业未来发展趋势!
  5. python+opencv 获取图像属性,获取图像感兴趣区域ROI
  6. 学渣都能看懂的-最小生成树Prim算法(普里姆算法)
  7. 20180929 北京大学 人工智能实践:Tensorflow笔记08
  8. ArcMap 投影变换
  9. lq_C/C++常见知识补充002
  10. 关闭所有oracle服务,启动/关闭oracle服务有三种方式