Welcome
2467 字
12 分钟
[搬运/翻译]缓存策略选择与业务场景:如何挑选最合适的方式?

原文:caching-strategies-and-how-to-choose-the-right-one 翻译、注释:Reisen


缓存是提升系统性能最简单也最有效的方法之一 。毕竟,数据库有时会显得有些慢(哪怕是 NoSQL 数据库),而在现代系统开发中,速度就是一切 。

如果运用得当,缓存不仅能缩短响应时间减轻数据库负载,还能有效节约成本 。然而,缓存策略多种多样,选对策略对系统表现有着决定性的影响 。

💡 核心法则: 系统的缓存策略完全取决于数据特性数据访问模式(Data Access Patterns) —— 换句话说,取决于你的数据是如何被写入和读取的 。

在选择策略前,可以先思考以下几个技术问题:

  • 系统是写密集型(Write-heavy)但读取频率较低吗?(例如:基于时间的日志)

  • 数据是一次写入、多次读取吗?(例如:用户档案(User Profile))

  • 返回的数据是否总是唯一的?(例如:搜索查询)

显而易见,一款移动游戏“前 10名 排行榜(Leaderboard)”系统所采用的缓存策略,与一个聚合并返回用户档案的服务是截然不同的 。

下面,我们来深入解析几种主流的缓存策略。

1. 旁路缓存 (Cache-Aside)#

这或许是实际项目中最常被使用的缓存方法 。在这种模式下,缓存“靠边站(On the side)”,应用程序直接与缓存和数据库两端进行通信 。缓存和主数据库之间没有任何直接的连接,所有的交互逻辑都由应用程序亲自处理 。

🔄 工作原理#

  1. 应用程序首先检查缓存 。

  2. 如果数据存在,即缓存命中(Cache Hit),直接读取数据并返回给客户端 。

  3. 如果数据不存在,即缓存缺失(Cache Miss),应用程序需要执行额外的工作:查询数据库获取数据、返回给客户端,同时将数据写入缓存,以便后续对相同数据的读取能够直接命中 。

⚖️ 优缺点与适用场景#

  • 最适合读密集型(Read-heavy)工作负载:如 Redis 和 Memcached 的经典应用 。

  • 具备缓存故障弹性(Resilience):如果缓存集群宕机,系统仍能通过直接访问数据库维持运行 。(注:如果系统在高峰期遭遇缓存雪崩,由于请求全部涌向数据库,响应时间可能会变得极差,甚至导致数据库瘫痪 。)

  • 数据模型灵活性:缓存中的数据模型可以与数据库不同。例如,可以将多个复杂查询聚合后的响应结果,直接以某个 Request ID 为 Key 存入缓存 。

  • 数据不一致风险:在使用 Cache-Aside 时,最常见的写策略是直接写入数据库 。这会导致缓存与数据库的数据产生不一致 。开发者通常会引入 TTL(生存时间),在数据过期前容忍读取脏数据 ;若对数据新鲜度(Freshness)有强要求,则需要手动使缓存失效(Invalidate)或搭配其他写策略 。

2. 读穿透缓存 (Read-Through)#

Read-Through 缓存与数据库处于同一线上(In-line) 。当发生缓存缺失(Cache Miss)时,它会自动从数据库加载缺失的数据,填充缓存,并将其返回给应用程序 。

Cache-AsideRead-Through 都是延迟加载(Lazy Loading)的——也就是说,只有在数据第一次被读取时,才会进入缓存 。

⚖️ 与 Cache-Aside 的关键区别#

  1. 职责划分:在 Cache-Aside 中,应用程序负责从数据库抓取数据并填充缓存 ;而在 Read-Through 中,这一逻辑通常由缓存库(Library)或独里的缓存提供商原生支持,应用层无需关心 。

  2. 数据模型:与 Cache-Aside 不同,Read-Through 缓存中的数据模型必须与数据库保持一致

⚖️ 优缺点与适用场景#

  • 适用场景:最适合相同数据被高频反复读取的读密集型场景(例如:热门新闻报道) 。

  • 缺点:当数据首次被请求时,必然会导致缓存缺失,并带来加载数据库的额外延迟惩罚 。

  • 解决方案:开发者通常会通过手动执行查询来“预热(Warming / Pre-heating)”缓存 。同样,它也会遇到数据不一致的问题,需要结合写策略来解决 。

3. 写穿透缓存 (Write-Through)#

在这种写策略中,数据首先被写入缓存,接着被同步写入数据库 。缓存与数据库同样是在线(In-line)的,所有的写操作必须“穿透”缓存才能到达主数据库 。

🔄 工作原理#

  1. 应用程序直接将数据写入缓存 。

  2. 缓存同步更新主数据库 。当写入完成时,缓存和数据库拥有完全相同的值,从而完美保证了数据一致性

⚖️ 优缺点与适用场景#

  • 缺点:由于每次都需要执行两次写操作(先写缓存,再写数据库),它引入了额外的写入延迟(Write Latency)

  • 最佳拍档Write-Through 单独使用时略显鸡肋,但当它Read-Through 配合使用时,就能发挥威力 。它不仅具备 Read-Through 的所有优势,还能提供强一致性保证,让开发者免受缓存失效(Cache Invalidation)逻辑的困扰(前提是所有写操作都必须经过缓存) 。

  • 典型代表Amazon DynamoDB Accelerator (DAX) 就是一个完美的 Read-Through / Write-Through 缓存示例 。它位于 DynamoDB 和应用程序之间,全权托管读写请求 。

4. 写绕过 (Write-Around)#

在这种模式下,数据直接写入数据库,完全绕过缓存 。只有当这些数据后续被读取时,它才会通过读策略进入缓存 。

⚖️ 优缺点与适用场景#

  • 最佳拍档:可以与 Read-ThroughCache-Aside 组合使用 。

  • 适用场景:在数据“一次写入,极少读取”甚至“不再读取”的业务场景下表现优异 。例如:实时日志(Real-time logs)聊天室历史消息(Chatroom messages) 。这种模式可以避免那些写入后无人问津的“垃圾数据”塞满缓存空间 。

5. 写回/异步写 (Write-Back / Write-Behind)#

在这种策略中,应用程序将数据写入缓存,缓存层在存储数据后,立刻向应用程序返回成功响应 。直到随后的某个时间点,缓存才会异步(Asynchronously)且批量地将数据刷入(Write-back)数据库 。

🔄 与 Write-Through 的本质区别#

  • Write-Through:数据写入缓存是同步(Synchronously)更新到主数据库的 。

  • Write-Back:数据写入缓存是异步(Asynchronously)更新到主数据库的 。从应用视角来看,写入速度极快,因为只要缓存更新完了就可以直接返回响应 。

⚖️ 优缺点与适用场景#

  • 优势:极大提升了写入性能,是写密集型(Write-heavy)工作负载的福音

  • 混合场景:与 Read-Through 结合时,非常适合混合型工作负载(Mixed Workloads),能确保最近更新和访问的数据始终在缓存中可用 。

  • 削峰降本:对数据库故障有一定的容忍度(即使数据库短暂宕机也能写入缓存) 。如果缓存支持批处理(Batching)或合并写入(Coalescing),它可以大幅减少对数据库的实际写入次数,从而减轻数据库压力,并在数据库按请求量计费时(如 DynamoDB)显著降低成本

  • 致命缺点:一旦缓存层发生故障或崩溃,未同步的数据可能会永久丢失

  • 现实应用:很多开发者利用 Redis 来兼顾 Cache-Aside(读)和 Write-Back(写),以更好地吸收高并发下的流量洪峰 。其实,大多数关系型数据库的存储引擎内部(如 MySQL 的 InnoDB)默认就开启了 Write-Back 机制:查询和修改先写入内存(Buffer Pool),后续再异步刷新(Flush)到磁盘上 。

🛠️ 总结与避坑指南#

缓存策略读操作写操作优点缺点适用场景
Cache-Aside先查缓存,缺失则查库并回写直接写库弹性高、数据模型灵活可能读到脏数据(需靠 TTL 缓解)通用场景、读密集型
Read-Through缓存缺失时,由缓存框架自动查库应用层代码干净、适合高频读首次读取有延迟(需缓存预热)读密集型、相同数据高频请求
Write-Through先写缓存,缓存同步写库数据强一致性写入延迟较高(两次写操作)配合 Read-Through 实现强一致性
Write-Around直接写库,绕过缓存避免冷数据污染缓存空间首次读取必定 Cache Miss一次写入、极少读取(如日志、聊天记录)
Write-Back只写缓存,异步批量刷库写入性能极高、可合并写降低数据库压力缓存宕机有丢失数据的风险写密集型、高并发削峰

⚠️ 选错策略的代价#

在架构设计中,必须仔细评估业务目标、理解数据的读写模式,从而选择最匹配的单一策略或组合策略 。

如果选错了策略,系统不仅无法享受缓存带来的红利,反而可能引入额外的延迟 。例如:如果你在数据“写多读少”的场景下错误地选择了 Write-Through / Read-Through,而不是 Write-Around / Read-Through,你的缓存中很快就会充斥着无人问津的垃圾冷数据

在内存资源昂贵、服务器成本高企的真实高并发、高吞吐系统中,内存永远是不够用的 。因此,结合业务场景选择正确的缓存策略,至关重要 。

[搬运/翻译]缓存策略选择与业务场景:如何挑选最合适的方式?
https://fuwari.vercel.app/posts/缓存策略选择与业务场景如何挑选最合适的方式/
作者
铃仙 Reisen
发布于
2026-06-13
许可协议
CC BY-NC-SA 4.0