
首先,我们必须明确一个核心观点:在分布式环境下,要实现强一致性(在任何时刻读取的数据都是最新的)是极其困难且代价高昂的,通常会严重牺牲性能。因此,在实践中,我们通常追求最终一致性,即允许在短暂的时间内数据不一致,但通过一些手段保证数据最终会保持一致。
下面我将从基础概念、各种策略、最佳实践到最新方案,为你详细讲解。
在一个包含 MySQL(作为可靠数据源)和 Redis(作为缓存)的系统中,所有的写操作(增、删、改)都必须同时处理这两个地方。

这个过程中,任何一步失败或延迟都会导致不一致:
解决双写一致性有多种策略,我们需要根据业务场景(对一致性的要求、读写的比例等)进行选择。
这是最常用、最经典的缓存模式。核心原则是:应用程序直接与数据库和缓存交互,缓存不作为写入的必经之路。
为什么是删除(Invalidate)缓存,而不是更新缓存? 这是一个关键设计点!
Cache-Aside 如何保证一致性? 它通过“先更新数据库,再删除缓存”来尽力保证。但它依然存在不一致的窗口期:
这种情况发生的概率较低,因为通常数据库写操作(步骤1)会比读操作(步骤2)耗时更长(因为涉及锁、日志等),所以步骤2在步骤1之前完成的概率很小。但这是一种理论上的可能。
在这种模式下,缓存层(或一个独立的服务)自己负责与数据库交互。对应用来说,它只与缓存交互。
优点:逻辑对应用透明,一致性比 Cache-Aside 更好。 缺点:性能较差,因为每次写操作都必然涉及一次数据库写入。通常需要成熟的缓存中间件支持。
Write-Through 的异步版本。应用写入缓存后立即返回,缓存组件在之后某个时间点(例如攒够一批数据或定时)批量异步地更新到数据库。
优点:写性能极高。 缺点:有数据丢失风险(缓存宕机),一致性最弱。适用于允许少量数据丢失的场景,如计数、点赞等。
为了弥补 Cache-Aside 模式中的缺陷,我们可以引入一些额外的机制。
针对 Cache-Aside 中提到的“先更新数据库,再删除缓存”可能带来的并发问题,可以引入一个延迟删除。
第二次删除是为了清理掉在第1次删除后、其他线程可能写入的旧数据。这个休眠时间需要根据业务读写耗时来估算。
优点:简单有效,能很大程度上解决并发读写导致的不一致。 缺点:降低了写入吞吐量,休眠时间难以精确设定。
为了解耦和重试,可以将删除缓存的操作作为消息发送到消息队列(如 RocketMQ, Kafka)。
这保证了删除缓存的操作至少会被执行一次,大大提高了可靠性。
这是目前最成熟、对业务侵入性最小、一致性最好的方案。其核心是利用 MySQL 的二进制日志(Binlog)进行增量数据同步。
工作原理:

优点:
缺点:
策略 | 一致性保证 | 性能 | 复杂度 | 适用场景 |
|---|---|---|---|---|
Cache-Aside + 删除 | 最终一致性(有微弱不一致风险) | 高 | 低 | 绝大多数场景的首选,读多写少 |
Cache-Aside + 延迟双删 | 更好的最终一致性 | 中 | 低 | 对一致性要求稍高,且能接受一定延迟的写操作 |
Write-Through | 强一致性 | 中 | 中 | 写多读少,且对一致性要求非常高的场景 |
Binlog 同步 | 最终一致性(推荐) | 高 | 高 | 大型、高要求项目的最佳实践,对业务无侵入 |
通用建议:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。