点击上方蓝色“程序猿DD”,选择“设为星标”

回复“资源”获取独家整理的学习资料!

作者 | stephanie Tang

来源 | stephanietang.github.io/2020/04/13/cache-pattern/

缓存由于其高性能,支持高并发的特性,在高并发的项目中不可或缺。被大家广泛使用的有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发布重大更新,关系到所有程序员!

雷军 26 年前写的代码,你见过吗?

如果MySQL引起CPU消耗过大,你会怎么优化?

2020 年开源许可证最新趋势:67% 为宽松许可证

GitHub 热榜:文字识别神器,超轻量级中文 OCR!

扫一扫,关注我

一起学习,一起进步

缓存模式以及缓存的数据一致性相关推荐

  1. net.conn read 判断数据读取完毕_高并发:缓存模式以及缓存的数据一致性

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

  2. 缓存模式【缓存使用几种模式】【刘新宇】

    缓存模式 1) Cache Aside 更新方式 先更新数据库,再更新缓存.这种做法最大的问题就是两个并发的写操作导致脏数据.如下图(以Redis和Mysql为例),两个并发更新操作,数据库先更新的反 ...

  3. 微软BI 之SSIS 系列 - Lookup 组件的使用与它的几种缓存模式 - Full Cache, Partial Cache, NO Cache...

    开篇介绍 先简单的演示一下使用 Lookup 组件实现一个简单示例 - 从数据源表 A 中导出数据到目标数据表 B,如果 A 数据在 B 中不存在就插入新数据到B,如果存在就更新B 和 A 表数据保持 ...

  4. 应用多级缓存模式支撑海量读服务

    缓存技术是一个老生常谈的问题,但是它也是解决性能问题的利器,一把瑞士军刀:而且在各种面试过程中或多或少会被问及一些缓存相关的问题,如缓存算法.热点数据与更新缓存.更新缓存与原子性.缓存崩溃与快速恢复等 ...

  5. 缓存模式(Cache Aside、Read Through、Write Through、Write Behind)

    概览 缓存是一个有着更快的查询速度的存储技术,这里的更快是指比起从初始的数据源查询(比如数据库,以下都称作数据库)而言.我们经常会把频繁请求的或是耗时计算的数据缓存起来,在程序收到请求这些数据的时候可 ...

  6. SQLite剖析之异步IO模式、共享缓存模式和解锁通知

    1.异步I/O模式     通常,当SQLite写一个数据库文件时,会等待,直到写操作完成,然后控制返回到调用程序.相比于CPU操作,写文件系统是非常耗时的,这是一个性能瓶颈.异步I/O后端是SQLi ...

  7. Tip: 强制 Outlook 用户使用缓存模式

    能否强制 Outlook 用户使用缓存模式 =========================== 可以.我们可以使用cmdlet Set-CASMailbox 来控制POP,MAPI,IMAP,EA ...

  8. 如果不知道这4种缓存模式,敢说懂缓存吗?

    概述 在系统架构中,缓存可谓提供系统性能的最简单方法之一,稍微有点开发经验的同学必然会与缓存打过交道,最起码也实践过. 如果使用得当,缓存可以减少响应时间.减少数据库负载以及节省成本.但如果缓存使用不 ...

  9. Firefox火狐浏览器web开发调试开启强制刷新缓存模式

    Firefox火狐浏览器web开发调试开启强制刷新缓存模式 最近做项目的时候,在火狐浏览器发现缓存难清理,用Ctrl+F5 Ctrl+R 等在谷歌和IE浏览器的快捷键没用,搜索了一下,发现火狐清理缓存 ...

最新文章

  1. 自动驾驶资料合集:视频、书籍与开源项目
  2. 肺炎疫情期间购买口罩小记
  3. 教你怎么上传本地代码到github
  4. qt 运行库 linux,linux(ubuntu) 版qt5.x安装的一些知识
  5. asp.net日历控件My97DatePicker下载地址
  6. 13亿美元的思想实验
  7. vm15不支持linux,每个处理程序的多个VMExtensions不支持操作系统类型'Linux
  8. java ArrayList源码分析(转载)
  9. ValueError: Duplicate plugins for name projector解决
  10. .net 按行切割数组
  11. hosts文件位置和修复hosts文件
  12. 时钟转盘html源代码
  13. selenium鼠标操作
  14. 第三章 初级像差理论与像差校正(理解有误,请不吝指正)
  15. 【GANs学习笔记】(一)初步了解GANs
  16. 深信服防火墙设备故障机的更换方法
  17. 用 Python 分析了所有微信好友,发现了一个秘密...
  18. 不思量,自难忘:我的10年程序生涯
  19. 14过去完成时 vs 现在完成时,过去完成时 vs 一般过去时 vs 过去将来时
  20. 公共号码池redis实现方案

热门文章

  1. linux su、su -和sudo的区别
  2. ARM通用NEON多媒体处理SIMD引擎
  3. linux命令less
  4. linux下vim命令详解
  5. Android利用ViewPager实现滑动广告板
  6. CentOS7.2 开启内网转发
  7. OpenStack-MitakaCentos7.2双节点搭建--(五)Neutron服务
  8. 7能看出圆的周长吗_分手后真的能看出一个人的人品吗
  9. android 开发环境简书,Android Studio 开发环境快速搭建
  10. icmp 报文中的进程号