1. 缓存一致性概述

1.1 什么是缓存一致性

缓存一致性(Cache Consistency)是指在分布式系统中,缓存层与数据库(或其他数据源)之间保持数据内容同步的程度。当业务数据在数据库中被更新后,缓存中对应的副本数据应当及时反映这一变化,否则就会出现“缓存与数据库数据不一致”的问题。

从技术实现角度看,缓存一致性包含两个核心维度:

  • 时间维度:数据更新后,缓存多久能感知并同步最新值
  • 空间维度:同一份数据在多个缓存节点或副本之间是否一致
核心公式: 缓存一致性 = 数据新鲜度 + 副本收敛速度 + 更新可见性
缓存一致性核心概念关系 缓存一致性 数据新鲜度 副本收敛速度 更新可见性 说明: • 数据新鲜度:缓存数据与源数据的时间差,差越小越一致 • 副本收敛速度:多级缓存或多副本场景下,数据同步到所有副本的速度 • 更新可见性:一个节点写入新值后,其他节点何时能读到该新值

1.2 为什么需要缓存一致性治理

在互联网高并发架构中,缓存是提升系统吞吐量的核心手段。然而,缓存与数据库之间的数据不一致会引发严重的业务问题。缓存一致性治理的目标是在性能与一致性之间找到可接受的平衡点。

治理维度 业务影响 典型后果
数据准确性 用户看到过期或错误数据 订单状态显示错误、库存超卖
系统可靠性 缓存穿透/雪崩风险增加 数据库压力飙升、服务降级
运维复杂度 排查问题困难 需要人工清理缓存、回滚数据
业务连续性 关键链路中断 支付、库存、价格等核心功能异常
治理红线: 对于金融、交易、库存等强一致性场景,缓存一致性治理不是可选项,而是必须项。一次缓存不一致导致的超卖或错账,可能造成百万级资损。

1.3 常见缓存不一致场景

在实际生产环境中,缓存不一致问题通常由以下六类典型场景引发。理解这些场景是制定治理策略的前提。

常见缓存不一致场景分类 缓存不一致场景 场景1:先写DB后删缓存 删除缓存失败导致脏数据 场景2:先删缓存后写DB 并发读请求回填旧数据 场景3:缓存穿透 大量请求绕过缓存直达DB 场景4:缓存击穿 热点Key过期瞬间高并发 场景5:缓存雪崩 大量Key同时过期或宕机 场景6:主从延迟 读写分离导致读到旧数据 场景详解: • 场景1-2:读写顺序问题,是缓存更新策略选择的核心矛盾 • 场景3-5:缓存失效问题,与过期策略、并发控制密切相关 • 场景6:数据复制问题,在读写分离架构中尤为突出 • 治理目标:针对不同场景选择对应的缓存更新策略和连接池参数

1.4 场景深度分析

以下对最典型的两个场景进行代码级分析,帮助理解不一致产生的根本原因。

场景1:先写数据库,后删缓存(Cache-Aside 模式)

// 伪代码:先写DB后删缓存
public void updateOrder(Order order) {
    // 1. 更新数据库
    orderDao.update(order);
    // 2. 删除缓存(可能失败)
    cache.delete("order:" + order.getId());
}

不一致原因: 步骤2删除缓存时,如果Redis宕机、网络超时或删除命令被丢弃,缓存中仍保留旧数据。后续读请求会命中旧缓存,直到缓存过期。

场景2:先删缓存,后写数据库

// 伪代码:先删缓存后写DB
public void updateOrder(Order order) {
    // 1. 删除缓存
    cache.delete("order:" + order.getId());
    // 2. 更新数据库(耗时较长)
    orderDao.update(order);
    // 3. 并发读请求在步骤1-2之间回填了旧数据
}

不一致原因: 在步骤1删除缓存后、步骤2更新数据库完成前,如果有并发读请求发现缓存为空,会从数据库读取旧数据并回填到缓存,导致缓存中永久存储旧值。

治理启示: 场景1和场景2揭示了缓存一致性治理的两个核心矛盾——更新顺序与并发控制。后续章节将围绕延迟双删、异步补偿、分布式锁等策略展开详细方案。

1.5 一致性治理的权衡模型

缓存一致性治理本质上是在以下三个目标之间寻找平衡:

目标 描述 典型策略 代价
强一致性 任何时刻缓存与DB完全一致 同步双写 + 分布式锁 性能下降50%-80%
最终一致性 允许短暂不一致,最终收敛 异步删除 + 过期机制 存在秒级不一致窗口
弱一致性 容忍较长时间不一致 仅依赖TTL过期 不一致窗口可达分钟级
课程核心观点: 没有银弹式的缓存一致性方案。治理的关键在于:
1. 识别业务场景对一致性的真实要求
2. 选择合适的缓存更新策略(延迟双删、异步队列、Binlog监听等)
3. 调优连接池参数,降低不一致窗口的持续时间