2. 缓存一致性定义:强一致性、弱一致性、最终一致性、读写一致性模型

在分布式缓存与数据库构成的混合存储体系中,“一致性”不再是一个单一维度的概念。不同业务场景对数据在缓存与后端存储之间同步的即时性、顺序性和可观测性有着截然不同的要求。本章从最严格的强一致性出发,逐步过渡到弱一致性与最终一致性,并重点剖析读写一致性模型——这是构建缓存闭环架构时最容易引发线上故障的根源。

2.1 一致性模型全景对比

下表从核心定义、典型实现、适用场景和容错代价四个维度,对四种主流一致性模型进行横向对比:

模型 核心定义 典型实现 适用场景 容错代价
强一致性 写入完成后,任何后续读取都能立即读到最新值 同步双写、分布式锁、两阶段提交 金融交易、库存扣减、配置中心 高延迟、低吞吐、可用性下降
弱一致性 写入后不保证立即读到最新值,只保证最终会收敛 异步写回、Cache-Aside 无锁模式 用户头像、日志聚合、非关键计数 低延迟、高吞吐、可容忍短暂不一致
最终一致性 在没有新写入的条件下,经过足够长时间后所有副本最终一致 DNS 缓存、CDN 边缘节点、Gossip 协议 内容分发、社交动态、推荐系统 延迟窗口可控、最终收敛
读写一致性 写入者自己总能读到最新值,其他用户可能读到旧值 Session 级缓存、写后读校验、本地时间戳 用户资料编辑、购物车、表单提交 仅保证写者自身视角,实现成本低
架构决策提示: 在缓存一致性闭环设计中,读写一致性 是最容易被忽视但影响面最大的模型。用户编辑完资料后刷新页面看到旧数据,往往不是缓存失效,而是读写一致性未被满足。

2.2 强一致性:同步屏障与线性化

强一致性要求系统对外表现为“单副本”行为——任何时刻、任何节点发起的读取操作,都必须返回最近一次写入的结果。在缓存场景中,这意味着缓存与数据库之间必须维持严格的同步屏障。

核心约束:
  • 写入操作必须等待缓存和数据库都确认后才返回成功。
  • 读取操作必须从最新副本(通常是主库或同步缓存)获取数据。
  • 分布式环境下需要引入分布式锁或 Paxos/Raft 协调写入顺序。

强一致性的典型实现路径:

  1. 同步双写(Write-Through): 应用层同时写入缓存和数据库,任一失败则回滚整个操作。
  2. 分布式锁 + 缓存失效: 写入前获取全局锁,写入后主动失效缓存,后续读取强制回源。
  3. 两阶段提交(2PC): 在缓存和数据库之间引入协调者,保证原子提交。
// 强一致性写入伪代码(同步双写)
boolean writeWithStrongConsistency(String key, Object value) {
    boolean dbSuccess = database.set(key, value);
    if (!dbSuccess) return false;
    boolean cacheSuccess = cache.set(key, value);
    if (!cacheSuccess) {
        // 缓存写入失败,回滚数据库
        database.delete(key);
        return false;
    }
    return true;
}
代价警示: 强一致性在分布式缓存中会显著降低可用性。当缓存节点故障时,写入操作必须等待超时或降级,容易引发连锁雪崩。实际工程中,99% 的缓存场景不需要全局强一致性。

2.3 弱一致性与最终一致性:异步收敛

弱一致性放弃“立即可见”的承诺,只保证数据最终会收敛到一致状态。最终一致性是弱一致性的一个特例——它额外承诺在没有新写入的情况下,经过一个有限的“不一致窗口”后,所有副本将达成一致。

最终一致性的关键参数:

  • 不一致窗口(Inconsistency Window): 从写入完成到所有副本读取到最新值的时间差。
  • 收敛速度: 取决于异步复制频率、网络延迟和冲突解决策略。
  • 冲突处理: 最后写入胜利(LWW)、向量时钟、CRDT 等。
工程实践: 在 Cache-Aside 模式中,最终一致性通过“先更新数据库,再失效缓存”实现。不一致窗口通常为缓存失效到下次回源的时间间隔,典型值为 1~10 毫秒。
// 最终一致性写入伪代码(Cache-Aside 模式)
void writeWithEventualConsistency(String key, Object value) {
    database.set(key, value);          // 1. 先更新数据库
    cache.delete(key);                 // 2. 再失效缓存(非删除,而是标记失效)
    // 后续读取会 miss 缓存,回源数据库并重建缓存
}

2.4 读写一致性模型:写者自见

读写一致性(Read-Your-Writes Consistency)是一种比最终一致性更强、比强一致性更弱的折中模型。它保证:写入者自己 在写入完成后发起的读取操作,一定能看到自己刚写入的数据;但其他用户或节点可能仍然读到旧值。

这一模型在缓存架构中极其重要,因为用户对“自己操作的结果”有最直接的感知预期。

实现读写一致性的三种常见策略:

策略 实现方式 优点 缺点
Session 级缓存 为每个用户 Session 维护一份私有缓存,写入后立即更新 Session 缓存 实现简单,隔离性好 Session 内存占用高,跨 Session 不共享
写后读校验 写入后立即从缓存读取一次,若不一致则强制回源 通用性强,不依赖 Session 增加一次额外读取开销
本地时间戳 写入时记录本地时间戳,读取时携带时间戳,缓存返回不早于该时间戳的数据 精确控制可见性 需要缓存支持时间戳比较
架构建议: 在用户资料编辑、购物车修改、表单提交等场景中,优先采用 Session 级缓存 + 写后读校验 的组合方案。前者保证写者自见,后者兜底异常情况。

2.5 一致性模型选择决策树

下图展示了在缓存一致性闭环架构中,如何根据业务需求选择合适的一致性模型:

缓存一致性模型选择决策树 业务写入请求 写入后是否必须立即被所有用户看到? 强一致性 同步双写 / 分布式锁 弱一致性 写入者自己是否必须立即看到? 读写一致性 Session缓存 / 写后读校验 最终一致性 异步复制 / Cache-Aside 决策原则:优先选择满足业务需求的最弱一致性模型 强一致性 → 读写一致性 → 最终一致性 → 弱一致性(从左到右代价递减)

2.6 一致性模型在缓存闭环中的映射

在《错误处理缓存一致性闭环架构》中,不同一致性模型对应不同的错误处理策略和闭环反馈机制:

  • 强一致性闭环: 写入失败时触发完整回滚(缓存 + 数据库),闭环检测周期短(毫秒级),错误处理成本高。
  • 读写一致性闭环: 写入失败时仅回滚写者自己的缓存视图,其他用户不受影响;闭环检测通过写后读校验触发。
  • 最终一致性闭环: 写入失败时依赖异步补偿任务(如定时对账)修复不一致,闭环检测周期长(秒级到分钟级)。
  • 弱一致性闭环: 几乎不设主动检测,依赖业务层幂等或用户刷新触发修复。
核心结论: 缓存一致性不是“全有或全无”的选择。在同一个系统中,不同数据可以共存不同的一致性模型。例如:库存数据使用强一致性,用户昵称使用最终一致性,购物车使用读写一致性。这种 混合一致性架构 是缓存闭环设计的核心实践。