51CTO

缓存由于其高性能,支持高并发的特性,在高并发的项目中不可或缺。被大家广泛使用的有Redis,Memcached等。本文主要探讨几种常见的缓存的读写模式,以及如何来保证缓存和数据库的数据一致性。

Cache-Aside

Cache-Aside可能是项目中最常见的一种模式。它是一种控制逻辑实现在应用程序中的模式。缓存不和数据库直接进行交互,而是由应用程序来同时和缓存以及数据库打交道。Cache-Aside的名字正体现了这个模式,Cache在应用的一旁(aside)。

读数据时

  1. 程序需要判断缓存中是否已经存在数据。
  2. 当缓存中已经存在数据(也就是缓存命中,cache hit),则直接从缓存中返回数据
  3. 当缓存中不存在数据(也就是缓存未命中,cache miss),则先从数据库里读取数据,并且存入缓存,然后返回数据

写数据时,我们可以有以下两种策略:

第一种策略:

  1. 更新数据库
  2. 更新缓存

但这种策略有线程安全的问题,可能出现缓存和数据库不一致。试想有两个写的线程,线程A和线程B

  1. A写数据库
  2. B后于A写数据库
  3. B写缓存
  4. A写缓存
  5. 缓存和数据库中的数据不一致,缓存中的是脏数据

要解决线程安全的问题,我们可以加锁,不过实现起来比较麻烦,因此我们不考虑这种写策略,而使用第二种策略。

第二种策略:

  1. 更新数据库
  2. 删除缓存中对应的数据

那么这种写策略会有线程安全的问题吗?有,试想一下有两个线程,线程A读,线程B写

  1. A读数据,由于未命中那么从数据库中取数据
  2. B写数据库
  3. B删除缓存
  4. A由于网络延迟比较慢,将脏数据写入缓存

但是这种情况可能性非常的小,需要同时满足很多条件,近乎不太可能发生,所以我们一般都采用这种写策略。另外可以对缓存中的数据设置合适的过期时间,即使发生的脏数据的情况,也不会发生很长时间。

应用场景

应用于缓存不支持
Read-Through/Write-Through的系统。

优点

  • 缓存仅仅保存被请求的数据,属于懒加载模式(Lazy Loading),和下文的Write-Through模式相比,避免了任何数据都被写入缓存造成缓存频繁的更新。

缺点

  • 当发生缓存未命中的情况时,则会比较慢,因为要经过三个步骤:查询缓存,从数据库读取,写入缓存。
  • 复杂的逻辑都在应用程序中,如果实现微服务,多个微服务中会有重复的逻辑代码

Read-Through/Write-Through

这种模式中,应用程序将缓存作为主要的数据源,而数据库对于应用程序是透明的,更新数据库和从数据库的读取的任务都交给缓存来代理了,所以对于应用程序来说,简单很多。

Read-Through

由缓存配置一个读模块,它知道如何将数据库中的数据写入缓存。在数据被请求的时候,如果未命中,则将数据从数据库载入缓存。

Write-Through

缓存配置一个写模块,它知道如何将数据写入数据库。当应用要写入数据时,缓存会先存储数据,并调用写模块将数据写入数据库。

应用场景

Read Through/Write Through适用于写入之后经常被读取的应用。

优点

  • 缓存不存在脏数据
  • 相比较Cache-Aside懒加载模式,读取速度更高,因为较少因为缓存未命中而从数据库中查找
  • 应用程序的逻辑相对简单

缺点

  • 对于总是写入却很少被读取的应用,那么Write-Through会非常浪费性能,因为数据可能更改了很多次,却没有被读取,白白的每次都写入缓存造成写入延迟。

除了Write-Through以外,我们还有另外的两种写模式可以和Read-Through一起来配合使用,分别是Write-Back和Write-Around。

Write-Back

又叫做Write-Behind。和Write-Through写入的时机不同,Write-Back将缓存作为可靠的数据源,每次都只写入缓存,而写入数据库则采用异步的方式,比如当数据要被移除出缓存的时候再存储到数据库或者一段时间之后批量更新数据库。

应用场景

读写效率都非常好,写的时候因为异步存储到数据库,提升了写的效率,适用于读写密集的应用。

优点

  • 写入和读取数据都非常的快,因为都是从缓存中直接读取和写入。
  • 对于数据库不可用的情况有一定的容忍度,即使数据库暂时不可用,系统也整体可用,当数据库之后恢复的时候,再将数据写入数据库。

缺点

  • 有数据丢失的风险,如果缓存挂掉而数据没有及时写到数据库中,那么缓存中的有些数据将永久的丢失了

Write-Around

和Write-Through不同,更新的时候只写入数据库,不写入缓存,结合Read-Through或者Cache-Aside使用,只在缓存未命中的情况下写缓存。

应用场景

适合于只写入一次而很少被读取的应用。

优点

  • 相比较Write-Through写入的时候的效率较高,如果数据写入后很少被读取,缓存也不会被没用到的数据占满。

缺点

  • 如果数据会写入多次,那么可能存在缓存和数据库不一致

转自:GitHub 作者: stephanie Tang

stephanietang.github.io/2020/04/13/cache-pattern/

高并发下如何保证缓存和数据库的数据一致性?相关推荐

  1. 高并发下如何保证接口的幂等性?

    前言 接口幂等性问题,对于开发人员来说,是一个跟语言无关的公共问题.本文分享了一些解决这类问题非常实用的办法,绝大部分内容我在项目中实践过的,给有需要的小伙伴一个参考. 不知道你有没有遇到过这些场景: ...

  2. session.merge 缓存不更新_如何保证缓存与数据库双写时的数据一致性?

    在做系统优化时,想到了将数据进行分级存储的思路.因为在系统中会存在一些数据,有些数据的实时性要求不高,比如一些配置信息.基本上配置了很久才会变一次.而有一些数据实时性要求非常高,比如订单和流水的数据. ...

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

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

  4. 如何保证缓存和数据库一致性?

    如何保证缓存和数据库一致性? 引入缓存提高性能 缓存利用率和一致性问题 并发引起的一致性问题 删除缓存可以保证一致性吗? 如何保证两步都执行? 主从延迟和延迟双删问题 可以做到强一致性吗? 总结 如何 ...

  5. 【另类见解】那些要保证缓存和数据库数据一致性的最后怎么了?

    " 现在如果说不出几句如何保证数据一致性方案的话,觉得出去面试都丢人,尤其是缓存和数据库的数据一致性 " 全程无图,请谨慎阅读 缓存对于程序性能而言,无疑是个杀手锏,但不是完美的解 ...

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

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

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

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

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

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

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

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

最新文章

  1. JVM运行时数据区---方法区(演变和垃圾回收)
  2. github访问不了_用ssh套娃翻到大陆公网给校园内网服务器装R包以及使用GitHub
  3. php循环语句for while do while的用法
  4. ERP_Oracle Erp 11i 和 R12的区别概述(概念)
  5. 大二上期计算机试题答案,2019年对口升学班上期期末计算机网络技术试卷及答案知识讲解.doc...
  6. CentOS 6.5 升级 PHP 到5.6
  7. 海量服务 | 论服务器极致化海量运营交付的未来
  8. openjdk_从CLI监视OpenJDK
  9. swift菜鸟入门视频教程-09-类和结构体
  10. 我的.NET开发环境设置
  11. linux clock命令,Centos Linux下使用date/clock/hwclock命令设置系统和硬件时间
  12. (转)(VS2013 )由于应用程序配置不正确,程序未能启动”--原因及解决方法...
  13. Java vbnullstring_VB中Null、Empty、Nothing及vbNullString的区别
  14. XPT2046 四线电阻式触摸屏
  15. 2021WSB-day2-4: Raffaele教授演示利用OpenCV和Python实现一个指纹识别系统 (含代码) part6
  16. jQuery 效果 ——fadeIn() 方法、fadeOut() 方法
  17. DSP内核结构中的 D L S M
  18. SQL 高级教程:SQL BETWEEN 操作符
  19. Linux系统中,python需要import上一级目录文件的解决办法
  20. LDAP 协议入门(轻量目录访问协议)

热门文章

  1. QQ号为什么值钱?QQ号价值评定方法解析
  2. Docker端口映射无法访问的问题排查
  3. linux ascii转换 utf8,C++中ASCII、unicode与Utf8之间的相互转化
  4. 华为网络设备升级系统
  5. 错误:找不到或无法加载主类 X.X.X.Application,解决办法
  6. 汤姆大叔的深入理解JavaScript读后感二(17——24节)
  7. MATLAB 复杂网络聚类系数代码
  8. 20051012: 神州六号发射成功
  9. linux lcd控制器刷新率,在Linux中 如何将LCD的刷新率降至 60Hz
  10. 黑社会交易用计算机,遭遇网络黑社会亲们都是怎么处理的