缓存更新策略总览:Cache Aside、Read/Write Through、Write Behind
数据库和缓存一致性的 Cache Aside、Read/Write Through、Write Behind 内容,讲清三种缓存更新策略的读写流程、责任边界和一致性代价。
相关工具
缓存更新策略先看谁负责
数据库和缓存一起用时,最容易出问题的不是读缓存,而是数据更新。读请求未命中,查数据库再写回缓存,这条链路很好理解;写请求来了以后,先改数据库还是先改缓存,更新缓存还是删除缓存,同步写还是异步写,这些选择会直接影响一致性和性能。
相关基础内容 在“如何保证数据库和缓存的一致性”里列了三类策略:Cache Aside、Read/Write Through、Write Behind。Cache Aside 是先从缓存读,没有就读数据库并写回缓存;更新数据时先持久化到数据库,再让缓存失效。Read/Write Through 是把更新数据库的操作交给缓存代理,应用认为后端是一个单一存储。Write Behind 是更新时只更新缓存,不更新数据库,由缓存异步批量更新数据库,优点是 I/O 很快,问题是数据不是强一致,而且可能会丢。
这三类策略的区别,可以先用一句话抓住:Cache Aside 由应用负责回源和失效;Read/Write Through 由缓存层代理后端存储;Write Behind 先写缓存,再异步落库。谁负责、什么时候写库、能不能接受延迟,这三个问题决定了策略适不适合你的业务。

Cache Aside 由应用负责读缓存、回源和失效;Read/Write Through 让缓存代理后端存储;Write Behind 先更新缓存,再异步批量写数据库。
Cache Aside:最常见,也最直接
Cache Aside 可以翻成旁路缓存。它的读流程是:应用先查 Redis,命中就返回;没命中再查 MySQL,把查询结果写回 Redis,然后返回给用户。文中的描述也是这个意思:先从缓存读取数据,如果没有就再去数据库里读,然后把数据放回缓存;如果缓存中可以找到数据就直接返回。
写流程通常是:应用先更新数据库,再让缓存失效。注意这里常说的是删除缓存或标记缓存失效,而不是一定同步更新缓存。这样下次读请求过来时,缓存未命中,会重新从数据库取新值并写回缓存。
这个模式的好处是简单,控制权在应用手里。应用知道什么时候读库、什么时候删缓存、哪些 key 需要失效。大多数业务系统采用的默认策略就是 Cache Aside,因为它实现成本低,也容易和现有 MySQL 写流程配合。
Cache Aside 的不一致窗口
资料 也指出了 Cache Aside 的问题。比如一个更新操作先更新数据库,还没来得及删除缓存,查询操作可能拿到旧数据。更新操作很快让缓存失效后,后续查询才能保证拿到新数据。也就是说,先写库再删缓存之间存在一个很短的旧值窗口。
另一个问题是读写并发:某个读请求没有命中缓存,于是到数据库取旧数据;这时来了一个写请求,写完数据库后删除缓存;随后那个较早的读请求又把旧数据写回缓存,就可能造成脏数据。资料 说这种问题出现概率比较低,因为需要同时满足读缓存失效、并发写,以及数据库读写时序刚好交错。
这不代表可以忽略。线上设计时,可以用较短 TTL、删除失败重试、消息队列补偿、延迟双删或 Binlog 订阅等方式降低风险。Cache Aside 不是完美一致方案,它是一个工程上常用、成本和收益比较平衡的方案。
Read Through:缓存层自己加载数据
资料 对 Read Through 的解释是:在查询操作中更新缓存;当缓存失效时,Cache Aside 是由调用方负责把数据加载入缓存,而 Read Through 则由缓存服务自己加载,对调用方透明。
换句话说,应用不再关心缓存命中还是未命中。应用只向缓存层请求数据,缓存层命中就返回;未命中时,缓存层自己去后端 Repository 或 MySQL 加载,再把结果放入缓存并返回给应用。应用看到的是一个统一的数据入口。
这个模式的优势是调用方简单。缓存逻辑被封装到缓存服务里,应用不用到处写“先查 Redis、未命中查库、再回填”的代码。代价是缓存层更重:它要知道如何加载数据,如何处理失败,如何组织后端访问,甚至要承载部分业务数据访问逻辑。
Write Through:缓存代理同步写库
资料 对 Write Through 的描述是:有数据更新时,如果没有命中缓存,直接更新数据库并返回;如果命中了缓存,则更新缓存,然后由缓存自己更新数据库,这是一个同步操作。
这个模式下,应用仍然把后端看成一个单一存储。写请求进入缓存层,缓存层负责判断缓存状态,并同步把更新写到数据库。它希望缓存和数据库在写路径上由同一个代理层维护,而不是让每个应用各自处理。
Write Through 的一致性比异步写更稳,因为写数据库是同步动作。缺点也明显:写入路径变长,缓存层要等数据库更新完成才能返回。对于写压力很高、延迟敏感的系统,这个同步成本不能忽略。
Through 模式适合缓存服务化
Read Through 和 Write Through 更适合缓存层被做成统一服务的场景。应用不直接管理 Redis key,也不直接处理回源和失效,而是调用一个数据访问层或缓存代理层。这个代理层知道数据怎么加载、怎么写库、怎么更新缓存。
它的好处是规范。多个应用不会各写一套缓存逻辑,缓存 key、TTL、回源、错误处理都可以集中管理。对于大型系统,这能减少重复代码,也能降低不同服务缓存策略不一致的问题。
但它也要求缓存代理层足够可靠。一旦代理层逻辑复杂,出了问题影响面会更大。相比 Cache Aside 的灵活简单,Through 模式更像基础设施设计。小团队或简单业务未必需要一开始就走这条路。
Write Behind:先快起来,再异步落库
资料 对 Write Behind 的描述很直接:更新数据时,只更新缓存,不更新数据库,而缓存会异步地批量更新数据库。好处是数据 I/O 操作非常快,问题是数据不是强一致的,而且可能会丢。
这个模式的写请求延迟很低。应用把数据写到缓存层后就可以返回,真正写数据库的动作放到后台批量执行。对高频写入、可以接受最终一致的统计类数据,这种方式有吸引力。
但它的风险也最大。缓存还没来得及落库时,如果 Redis 故障、进程异常、队列丢失,就可能丢数据。数据库不是第一时间更新,读数据库也可能看到旧值。它追求的是写入速度,不是强一致。
Write Behind 不能随便用于核心数据
Write Behind 很容易让人心动,因为写路径太快了。但越快的异步方案,越要问清楚失败怎么处理。订单、支付、余额、库存这类核心事实,通常不适合只写缓存再异步落库。即使后面有补偿,也要有可靠日志、重试、幂等和审计。
它更适合可丢一点、可重算、对实时持久化要求不高的数据。比如某些统计、日志聚合、短期行为计数、热度分更新。即便如此,也要设计后台批量写入、失败重试、积压监控和降级策略。
文中说它可能会丢,这句话要认真对待。不是所有“最终一致”都能被业务接受。有些数据丢一点只是统计偏差,有些数据丢一点就是事故。
三种策略怎么选
常规业务优先考虑 Cache Aside。它简单,应用可控,和 MySQL 主数据源配合自然。读多写少的缓存场景,用它最容易落地。只要配合合理 TTL、缓存删除、失败重试和监控,能覆盖很多系统。
如果希望应用不感知缓存细节,并且有能力建设统一缓存代理层,可以考虑 Read/Write Through。它把缓存加载和数据库更新封装在缓存服务里,对调用方透明,但会增加缓存层复杂度。
只有在特别追求写入性能,且业务能接受异步落库、最终一致甚至少量丢失时,才考虑 Write Behind。它不是通用缓存策略,更像特定高吞吐场景下的性能方案。
面试可以这样回答
如果被问数据库和缓存一致性策略,可以先说三类:Cache Aside、Read/Write Through、Write Behind。Cache Aside 是最常见的旁路缓存,读时先查缓存,未命中查数据库并回填;写时先更新数据库,再让缓存失效。
Read/Write Through 是让缓存代理后端存储。Read Through 在缓存失效时由缓存服务自己加载数据,对调用方透明;Write Through 在写入时由缓存层同步更新缓存和数据库,调用方认为后端是一个单一存储。
Write Behind 是写请求只更新缓存,由缓存异步批量写数据库。它写入很快,但不是强一致,故障时可能丢数据。最后补一句选型:常规业务优先 Cache Aside;需要统一代理再考虑 Through;能接受最终一致和丢失风险,才考虑 Write Behind。
常见问题
Cache Aside 的读写流程是什么?
读时先查缓存,未命中再查数据库并写回缓存;写时先更新数据库,再删除或让缓存失效。
Read Through 和 Cache Aside 有什么区别?
Cache Aside 由应用负责回源和写回缓存;Read Through 由缓存服务自己加载后端数据,对调用方透明。
Write Through 是同步还是异步?
Write Through 是同步写。命中缓存时更新缓存,并由缓存层同步更新数据库。
Write Behind 最大风险是什么?
它只先更新缓存,再异步批量写数据库,因此不是强一致;如果缓存或异步链路故障,可能丢数据。