本文深入探讨了后端架构中的缓存模式剖析了各种模式的优缺点及数据一致性表现。文章从面试准备、切入技巧入手详细解析了Cache Aside、Read Through、Write Through、Write Back等主流缓存模式并提供了异步加载、延迟双删等解决方案。强调缓存模式的核心是性能与一致性的权衡并通过装饰器模式展示了缓存架构的落地实践。适合程序员小白及有经验开发者学习助其在面试和项目实践中应对缓存挑战。1、 面试准备在准备面试前你不能只靠死记硬背。作为架构师或者是资深后端开发你需要对自己的知识库了如指掌。首先确保你不仅记住了这些模式的名字还能画出它们的时序图。其次你需要深挖一下你当前所在公司的实际情况你们现在的系统架构中到底落地了哪些缓存模式在这些模式下有没有爆发过数据不一致的生产事故最后是怎么填坑的在具体的业务流程中引入缓存后你是如何编排缓存更新与数据库更新顺序的是否存在一致性隐患把缓存模式吃透不仅能帮你应对数据一致性的难题更是解决后续我们将会讲到的缓存穿透、缓存击穿和缓存雪崩这“三座大山”的基石。这两个话题紧密相连在复习时要融会贯通。为了让你更直观地理解我们在脑海中构建一个简化的系统模型你的应用服务需要同时操作缓存Cache和数据库DB所有的读写请求都在这两个组件之间周旋。2、 面试切入在面试最开始的自我介绍环节你就可以埋下伏笔。你可以这样说“我对高并发场景下的缓存模式有比较深刻的实践心得在过往的项目中我经常通过灵活运用不同的缓存模式来解决系统面临的缓存穿透、雪崩以及热点击穿等问题。”这短短一句话既展示了你的技术深度又自然地引出了后续的话题。面试官听到这里大概率会顺水推舟地问“那你详细说说你都了解哪些缓存模式或者在项目中用过哪些”这时候你就可以如数家珍地抛出你的知识储备“在业界主流的实践中常见的缓存模式包括 Cache Aside、Read Through、Write Through、Write Back 以及 Singleflight。此外虽然严格意义上不算标准模式但在实际工程中删除缓存和延迟双删也是我们经常采用的策略。”这个回答既全面又接地气覆盖了理论与实战。接下来我们就一个个拆解这些模式。3、Cache AsideCache Aside可以说是业界应用最广泛的缓存模式了。Cache Aside的核心在于应用程序在数据流转中的定位。在这种模式下缓存仅仅是一个辅助的数据存储应用程序直接与数据库进行交互并全权负责维护缓存与数据库之间的数据状态。应用程序在这里扮演了数据流转的“总指挥”或“调度员”的角色它需要同时感知并操作 DB 和 Cache 两个数据源而不是让缓存组件去自动代理数据库的访问。写操作流程当业务发起写操作时Cache Aside Pattern 遵循以下严格的执行顺序更新数据库应用程序首先将变更的数据持久化到数据库中。删除缓存紧接着应用程序直接将该数据对应的缓存 Key 删除而不是尝试去更新它。为了更直观地理解这个过程请看下方的流程示意图读操作流程相较于写操作读操作的链路稍微复杂一些因为它涉及“命中”与“未命中”的分支处理查询缓存应用程序首先尝试从 Cache 中获取数据。缓存命中如果在缓存中找到了数据Hit直接返回结果流程结束。缓存回填如果缓存中没有数据Miss应用程序需要转向数据库发起查询。成功拿到数据后由应用程序显式地将数据写入缓存最后将结果返回给调用方。读操作的详细流转逻辑如下图所示3.1 亮点展示如果你仅仅掌握了上述的操作步骤那只能算是入门。在高级技术面试中面试官往往会针对这些“标准步骤”进行连环追问旨在考察你对并发一致性、性能权衡的深度理解。写操作为什么必须是“先更新 DB后删除 Cache”顺序能不能反过来这是一个非常高频的陷阱题。**结论是绝对不能反过来。**如果你采取“先删除 Cache后更新 DB”的策略在高并发场景下极易引发严重的数据不一致问题且该脏数据很难自动恢复。假设我们有一个商品库存的场景当前库存为 100。线程 A写请求准备将库存修改为 99。线程 B读请求并发查询该库存。如果顺序反了先删后写时序可能如下线程 A执行先删除了 Cache 中的库存数据。线程 B进场发现 Cache 为空Miss。它立即去查 DB但此时线程 A 还没来得及更新 DB所以线程 B 读到的是旧值 100。线程 B将读到的旧值 100 写入 Cache。线程 A终于完成了 DB 的更新将数据改为 99。最终结果数据库里是新的 99但缓存里永远停留在了旧的 100。后续所有的读请求都会命中这个脏数据直到缓存过期。这在很多业务中是不可接受的。那“先更新 DB后删除 Cache”就能保证数据一致吗结论是从理论上讲它也不是绝对安全的依然存在数据不一致的概率但这个概率极低工程上通常可以忽略。让我们看看这种“理论上的极端情况”是如何发生的这种情况发生的前提是缓存刚好失效Empty同时发生并发读写。线程 A读请求发现缓存未命中去查询 DB读取到了旧值比如 100。线程 B写请求在线程 A 读完 DB 但还没来得及回填 Cache 的瞬间线程 B 介入了。它迅速完成了 DB 更新改为 99并且完成了删除 Cache 的动作。线程 A读请求此时才开始执行“回填缓存”的动作它拿着刚才读到的旧值 100写入了 Cache。最终结果DB 是新值 99Cache 是旧值 100。为什么说概率极低这就涉及到了数据库与缓存操作耗时的对比。要发生上述情况要求“线程 A 从读完 DB 到写入 Cache”这一小段逻辑的执行时间竟然要比“线程 B 完成整个 DB 更新 Cache 删除”的时间还要长。在实际生产环境中数据库的写操作涉及锁、磁盘 I/O通常比纯内存的缓存操作要慢得多。读请求通常也会比写请求快。因此读请求“卡”在中间正好让写请求完整执行完一整套流程的情况发生的概率微乎其微。4、 同步更新前面说的Cache Aside 是删除缓存的一种策略那我们可不可以再更新完数据库之后同步更新缓存呢说实话同步更新很难被称为一种设计好的“模式”因为它本质上就是我们“什么都不封装”时的自然写法。在这个模式下业务代码把缓存视为一个与数据库平起平坐的独立数据源。所有的逻辑判断、读写顺序全靠业务代码自己来掌控。先来看写操作。当业务需要更新数据时由业务代码控制写入流程。再来看读操作。同样是由业务代码亲自操刀。在这个环节你需要向面试官介绍清楚读写的基本时序。它的核心逻辑是业务代码显式地处理缓存和数据库。一般业界的最佳实践是优先写入数据库。如果面试官追问“为什么要先写库而不是先写缓存”你要稳稳地接住“因为在绝大多数核心业务场景中数据库才是数据的最终真理Source of Truth。只要数据成功写入了数据库我们就可以认为这次业务操作是成功的。即便随后的缓存写入或更新失败了缓存本身有过期时间或者下次读取时发现缓存缺失会重新加载数据最终会恢复一致。”讲完这些你必须补上一句至关重要的总结这是体现你架构深度的关键“但是老实说无论是先写数据库还是先写缓存这种同步更新的模式本身都无法保证数据的强一致性。”这句话往往会激起面试官的兴趣他可能会问“为什么都不能解决在什么场景下会不一致”这时你就可以用下面这张图来做降维打击。为了方便记忆我教你一个口诀盯住图中的“线程2”它总是姗姗来迟后开始却总是捷足先登先结束。举个具体的例子假设我们库存原本是 100。线程1想要把库存更新为 10它先更新了数据库DB10。紧接着线程2想要把库存更新为 20它动作很快一口气更新了数据库DB20并且更新了缓存Cache20。这时候线程1才慢悠悠地执行它的第二步更新缓存Cache10。结果是什么数据库里是正确的 20但缓存里却是过期的 10。如果不加控制直到缓存过期前用户看到的都是错误的库存。5、Read ThroughCache Aside的问题在于业务代码太累了既要管库又要管缓存。于是有了Read Through也就是读穿透模式。它的核心理念是业务方你只管找缓存要数据如果缓存里没有缓存组件自己会去数据库加载数据并把自己喂饱。在写入方面Read Through通常和同步更新 保持一致没有什么特殊魔法。你可能会发现Read Through 只是封装了“读”的逻辑对于“写”的过程它依然很原始。所以它在数据一致性上的表现和 Cache Aside 是半斤八两依然存在并发导致的数据不一致问题。如果面试官问到这儿你直接复用 同步更新的分析逻辑即可。但是Read Through 给架构师留了一个“后门”这也是它的高光时刻——异步化。5.1 亮点方案异步加载当 Read Through 发现缓存未命中时标准的做法是同步去查库。但我们可以把“加载数据”和“写入缓存”这两个动作解耦引入异步机制。变种一异步回写当从数据库查到数据后立刻把数据返回给业务方然后启动一个后台线程异步地把数据写入缓存。既然回写缓存可以异步那能不能把从数据库加载数据也异步了变种二全异步加载这招更激进。当缓存未命中时直接给业务方返回一个默认值或者错误码然后由缓存组件在后台异步地发起数据库查询并更新缓存。相比第一种变种第二种的缺陷很明显业务方在当次调用中拿不到真数据。场景选择如果你的业务对**响应时间RT**有着近乎变态的苛刻要求可以考虑变种二。代价是业务方必须能容忍短暂的降级数据。而变种一的收益其实相对有限除非你的缓存写入操作非常慢比如要存储一个巨大的对象或者需要进行复杂的序列化这时候异步回写才有意义。如果你在实际项目中用过这些变种一定要结合具体的业务场景比如电商的热门推荐列表、非关键配置信息等来举例说服力会倍增。6、 Write Through既然读可以穿透写自然也可以。Write Through写穿透是指当业务方需要写入数据时只负责写入缓存然后由缓存组件代替业务方去更新数据库。对于读操作Write Through 和 Cache Aside 是一样的。这里有几个细节值得注意Write Through 并没有强制规定是先刷库还是先刷缓存但在实际落地中为了数据安全通常也是优先保证数据库落盘。如果缓存中原本没有这条数据写入时要不要顺便更新缓存一般策略是如果预判这条数据马上会被读到那就顺手刷新缓存否则可以只写库等下次读的时候再懒加载。同样Write Through 也没能解决并发写的一致性死结。6.1 亮点方案异步写的权衡和 Read Through 类似Write Through 也可以玩异步。比如写入缓存后立刻给业务方返回“成功”然后后台异步去写库。这种模式有一个致命硬伤丢数据。如果缓存组件在回复“成功”后还没来得及写库就宕机了那这笔数据就彻底蒸发了。稍微稳妥一点的变种是同步写库但是异步刷新缓存。这种变种适合那种“写库很快但刷缓存很慢”的奇葩场景比如缓存结构非常复杂。但无论哪种异步风险都伴随着收益并存。7、Write Back如果你追求极致的写性能Write Back回写模式绝对是你的菜。它的特征非常鲜明写入数据时只更新缓存直接返回。数据库的更新被推迟到缓存数据过期或被逐出时触发。具体的流程是业务代码只管写缓存。后台有一个守护组件监听缓存中 Key 的过期事件一旦过期就将最新数据刷回数据库。显而易见这有个巨大的隐患如果缓存突然宕机所有未刷回数据库的脏数据将全部丢失。这也注定了 Write Back 只能用于那些对数据丢失有一定容忍度或者缓存层做到了极高可用性的场景。但这里有一个反直觉的结论也是你可以用来惊艳面试官的亮点“Write Back 虽然容易丢数据但在数据一致性方面它其实比 Cache Aside 表现得更好。”为什么我们需要分情况讨论。如果是本地缓存多节点那肯定不一致。但如果是集中式缓存如 Redis在不考虑缓存崩盘导致数据丢失的前提下它是可以做到逻辑闭环的。我们需要一步步引导面试官理解这个逻辑第一步写的一致性在使用 Redis 的场景下因为所有的写操作都只更新缓存对于业务方来说读也是读缓存。在这个封闭的闭环里业务方读到的永远是它刚刚写入的数据是自洽的。 虽然数据库里的数据滞后了但对业务无感。第二步读的一致性隐患当业务方去读数据发现缓存没了过期或被逐出需要去数据库加载。这时候可能会出问题读请求去数据库捞到了旧数据比如balance100。还没来得及回填缓存突然来了一个写请求把缓存设为了新值balance200。读请求动作慢了半拍把旧数据balance100回填到了缓存覆盖了新值。第三步解决方案解决思路也很经典——利用 Redis 的 SETNX 指令。当读请求回填缓存时不要直接SET而是用SETNXSet if Not Exists。只有当缓存里真的没有数## 据时才允许回填。如果缓存里已经有值了说明被写请求抢先更新了读请求就放弃回填直接用缓存里的新值。最后你可以用一句总结来一锤定音“因此Write Back 除了有数据丢失的风险外在缓存一致性的表现上其实优于其他模式。”这是一个比较激进的观点使用时要观察面试官的反应。如果他比较保守你可以改口说“Write Back 极大地缓解了数据不一致的问题。”8、 Refresh AheadRefresh Ahead预刷新模式在CDCChange Data Capture技术普及后变得非常流行。简单来说就是业务方只管写数据库通过监听数据库的 Binlog比如利用 Canal 组件来异步刷新缓存。这种模式把缓存的更新逻辑从业务代码中剥离了出来。但它同样面临并发魔咒。在数据写入数据库之后、Binlog 被消费并刷新到缓存之前这段时间窗口内数据是不一致的。更糟糕的是读写并发场景如果读请求在缓存未命中时去查库查到旧值恰好此时写请求改了库并且 Binlog 异步刷新了缓存新值。读请求如果晚一步回填缓存就会把新值覆盖掉。解决方案和 Write Back 如出一辙在读请求回填缓存时使用 SETNX。这样就能完美规避大部分并发导致的不一致。9、 SingleflightSingleflight严格来说不是一种读写模式而是一种流量控制模式。它的原理非常简单直接当缓存未命中时如果同时有一万个请求去查同一个 Key比如突发热点新闻Singleflight 机制保证只有一个线程真正去数据库加载数据其他 9999 个线程都在原地阻塞等待这个结果。这个模式的核心价值在于保护数据库防止缓存击穿导致的数据库瞬间雪崩。它最大的优点是极大地减轻了数据库的并发压力。缺点是如果并发量本来就不高这套机制就显得有点鸡肋。所以它特别适合**热点数据Hot Key**的场景。10、 删除缓存这可能是业务开发中最常见的用法。也就是更新数据时先更新数据库然后直接把缓存删掉。这种做法也可以结合Write Through模式来做让缓存组件去更新数据库然后缓存组件自己把自己删了。为什么是删而不是更新因为“更新”动作可能涉及复杂的计算而且可能你费劲更新了缓存结果一直没人读浪费了性能。删除则是懒加载的思想。但“先改库后删缓存”就没问题了吗当然有。它的一致性隐患在于读线程缓存未命中撞上了写线程。读线程发现缓存空了去查库查到了旧值balance100。在读线程回填缓存之前写线程进来了改了库balance200。写线程为了保证一致性把缓存删了虽然此时缓存本来就没数据。这时候读线程才慢悠悠地把刚才查到的旧值balance100写入缓存。结果数据库是 200缓存是 100脏数据出现了。为了解决这个极低概率但理论上存在的 Bug架构圈发明了延迟双删。10.1 延迟双删看名字就知道这个模式要删两次。基本流程是先删缓存可选 - 写数据库 - 删缓存 - (休眠 N 毫秒) - 再次删缓存。重点在于这第二次删除。为什么要有第二次删除就是为了防备像上面提到的那个“读线程”把脏数据回写进去。通过设定一个短暂的延迟比如 500ms让读线程有足够的时间把脏数据写完然后我们再来一次“回马枪”把这个脏数据删掉。那是不是就绝对完美了从理论上讲依然存在极端情况。比如读线程在第二次删除之后才回写缓存那还是会不一致。但在现实世界中这种情况发生的概率比中彩票还低。因为数据库主从同步、网络传输的耗时通常远大于代码执行的耗时只要你延迟的时间设置得当覆盖主从同步延迟 几百毫秒延迟双删基本能解决 99.99% 的问题。不过延迟双删也有代价降低了缓存命中率因为你删了两次中间这段时间缓存是空的。增加了系统复杂度你需要维护延迟逻辑。11、 缓存模式到底该选哪个讲了这么多模式面试官最后肯定会问你“那在你的项目中你建议用哪个”这时候切忌给出一个标准答案因为架构设计没有银弹。任何一种模式都有缺陷。你可以这样回答“实际上选择哪种模式取决于业务的具体权衡。如果业务对数据一致性要求极高比如金额我们通常不走缓存或者加分布式锁但这会牺牲性能。对于大多数常规业务如果你问我标准答案我会推荐延迟双删。虽然它稍微降低了缓存命中率但在我们的大部分业务并发量级下这是一个性价比极高的方案能覆盖绝大多数一致性问题。如果是写多读少或者对数据丢失不敏感的统计类业务如点赞数我会尝试Write Back。”11.1 亮点用装饰器模式落地缓存模式光说不练假把式。如果在面试中你想进一步展示你的代码架构能力可以提一下装饰器模式Decorator Pattern。你可以说“在公司内部为了避免业务团队乱用缓存模式我设计了一套统一的缓存 SDK。我定义了一个标准的Cache接口然后利用装饰器模式无侵入地实现了上述的大部分模式。”这里我给出一个Read Through模式的伪代码实现逻辑供你参考// 1. 定义标准接口type Cache interface { Get(key string) any Set(key string, val any)}// 2. 定义 ReadThrough 装饰器结构体type ReadThroughCache struct { c Cache // 持有基础缓存实例如 Redis 或 本地内存 fn func(key string) any // 数据加载函数回源逻辑}// 3. 实现 Get 方法植入 Read Through 逻辑func (r *ReadThroughCache) Get(key string) any { // 先查缓存 val : r.c.Get(key) // 缓存未命中 if val nil { // 调用回源函数加载数据 val r.fn(key) // 回写缓存 r.c.Set(key, val) } return val}你可以这样包装你的项目经历“我把这个设计封装成了通用的中间件。对于业务开发者来说他们只需要初始化这个装饰器传入数据加载逻辑就能自动获得 Read Through 甚至 Singleflight 的能力既规范了代码又屏蔽了底层复杂性。”这话说出来面试官对你的评价绝对会上升一个台阶。12. 小结这篇文章我们抽丝剥茧层层深入地分析了Cache Aside、同步更新、Read Through、Write Through、Write Back、Refresh Ahead和Singleflight以及删除缓存和延迟双删策略。但是你要记住缓存模式虽然多其核心矛盾永远是性能与一致性的博弈。当你能够清晰地指出每种模式在什么极端并发下会出问题并且给出SETNX或延迟双删这样的解决方案时你就已经超越了绝大多数候选人。希望这篇文章能帮你打通缓存架构的任督二脉让你在项目实践和面试过程中都能有所收获最后对于正在迷茫择业、想转行提升或是刚入门的程序员、编程小白来说有一个问题几乎人人都在问未来10年什么领域的职业发展潜力最大答案只有一个人工智能尤其是大模型方向当下人工智能行业正处于爆发式增长期其中大模型相关岗位更是供不应求薪资待遇直接拉满——字节跳动作为AI领域的头部玩家给硕士毕业的优质AI人才含大模型相关方向开出的月基础工资高达5万—6万元即便是非“人才计划”的普通应聘者月基础工资也能稳定在4万元左右。再看阿里、腾讯两大互联网大厂非“人才计划”的AI相关岗位应聘者月基础工资也约有3万元远超其他行业同资历岗位的薪资水平对于程序员、小白来说无疑是绝佳的转型和提升赛道。对于想入局大模型、抢占未来10年行业红利的程序员和小白来说现在正是最好的学习时机行业缺口大、大厂需求旺、薪资天花板高只要找准学习方向稳步提升技能就能轻松摆脱“低薪困境”抓住AI时代的职业机遇。如果你还不知道从何开始我自己整理一套全网最全最细的大模型零基础教程我也是一路自学走过来的很清楚小白前期学习的痛楚你要是没有方向还没有好的资源根本学不到东西下面是我整理的大模型学习资源希望能帮到你。扫码免费领取全部内容最后1、大模型学习路线2、从0到进阶大模型学习视频教程从入门到进阶这里都有跟着老师学习事半功倍。3、 入门必看大模型学习书籍文档.pdf书面上的技术书籍确实太多了这些是我精选出来的还有很多不在图里4、AI大模型最新行业报告2026最新行业报告针对不同行业的现状、趋势、问题、机会等进行系统地调研和评估以了解哪些行业更适合引入大模型的技术和应用以及在哪些方面可以发挥大模型的优势。5、面试试题/经验【大厂 AI 岗位面经分享107 道】【AI 大模型面试真题102 道】【LLMs 面试真题97 道】6、大模型项目实战配套源码适用人群四阶段学习规划共90天可落地执行第一阶段10天初阶应用该阶段让大家对大模型 AI有一个最前沿的认识对大模型 AI 的理解超过 95% 的人可以在相关讨论时发表高级、不跟风、又接地气的见解别人只会和 AI 聊天而你能调教 AI并能用代码将大模型和业务衔接。大模型 AI 能干什么大模型是怎样获得「智能」的用好 AI 的核心心法大模型应用业务架构大模型应用技术架构代码示例向 GPT-3.5 灌入新知识提示工程的意义和核心思想Prompt 典型构成指令调优方法论思维链和思维树Prompt 攻击和防范…第二阶段30天高阶应用该阶段我们正式进入大模型 AI 进阶实战学习学会构造私有知识库扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架抓住最新的技术进展适合 Python 和 JavaScript 程序员。为什么要做 RAG搭建一个简单的 ChatPDF检索的基础概念什么是向量表示Embeddings向量数据库与向量检索基于向量检索的 RAG搭建 RAG 系统的扩展知识混合检索与 RAG-Fusion 简介向量模型本地部署…第三阶段30天模型训练恭喜你如果学到这里你基本可以找到一份大模型 AI相关的工作自己也能训练 GPT 了通过微调训练自己的垂直大模型能独立训练开源多模态大模型掌握更多技术方案。到此为止大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗为什么要做 RAG什么是模型什么是模型训练求解器 损失函数简介小实验2手写一个简单的神经网络并训练它什么是训练/预训练/微调/轻量化微调Transformer结构简介轻量化微调实验数据集的构建…第四阶段20天商业闭环对全球大模型从性能、吞吐量、成本等方面有一定的认知可以在云端和本地等多种环境下部署大模型找到适合自己的项目/创业方向做一名被 AI 武装的产品经理。硬件选型带你了解全球大模型使用国产大模型服务搭建 OpenAI 代理热身基于阿里云 PAI 部署 Stable Diffusion在本地计算机运行大模型大模型的私有化部署基于 vLLM 部署大模型案例如何优雅地在阿里云私有部署开源大模型部署一套开源 LLM 项目内容安全互联网信息服务算法备案…扫码免费领取全部内容3、这些资料真的有用吗这份资料由我和鲁为民博士(北京清华大学学士和美国加州理工学院博士)共同整理现任上海殷泊信息科技CEO其创立的MoPaaS云平台获Forrester全球’强劲表现者’认证服务航天科工、国家电网等1000企业以第一作者在IEEE Transactions发表论文50篇获NASA JPL火星探测系统强化学习专利等35项中美专利。本套AI大模型课程由清华大学-加州理工双料博士、吴文俊人工智能奖得主鲁为民教授领衔研发。资料内容涵盖了从入门到进阶的各类视频教程和实战项目无论你是小白还是有些技术基础的技术人员这份资料都绝对能帮助你提升薪资待遇转行大模型岗位。这份完整版的大模型 AI 学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】