1. 缓存一致性概述
1.1 什么是缓存一致性
缓存一致性(Cache Consistency)是指在分布式系统中,缓存层与底层数据库(如 MySQL、PostgreSQL)之间存储的数据保持相同或可接受偏差的状态。当业务数据发生变更时,缓存中的副本必须与数据库中的主本在逻辑上对齐,否则系统将面临数据错乱、业务逻辑错误甚至资损风险。
核心定义:缓存一致性 = 缓存数据与数据库数据在任意时刻的“等价程度”。严格一致性要求两者完全相等;最终一致性允许短暂偏差,但必须在可接受的时间窗口内收敛。
在 Redis 作为缓存层的架构中,一致性通常不是二进制(0 或 1)的,而是一个时效性 + 正确性的组合指标:
- 强一致性:每次读操作都能读到最近一次写操作的结果,缓存与数据库实时同步。
- 最终一致性:允许写入后缓存短暂滞后,但经过异步任务或补偿机制后最终对齐。
- 弱一致性:不保证缓存与数据库的同步时间,业务需容忍数据过期。
| 一致性级别 | 延迟容忍 | 实现成本 | 典型场景 |
|---|---|---|---|
| 强一致性 | 零容忍 | 高(分布式锁、同步写穿透) | 金融交易、库存扣减 |
| 最终一致性 | 秒级~分钟级 | 中(异步任务、消息队列) | 用户资料、商品详情 |
| 弱一致性 | 分钟级以上 | 低(TTL 过期) | 排行榜、非关键统计 |
1.2 为什么需要缓存一致性
缓存一致性不是可选项,而是分布式系统数据正确性的底线保障。以下四个维度说明其必要性:
- 业务正确性:用户看到的价格、库存、订单状态必须真实有效,过期或错乱的缓存数据会直接导致资损或客诉。
- 系统可靠性:不一致的缓存可能掩盖数据库的真实状态,导致故障排查困难、数据修复成本飙升。
- 运维可观测性:当缓存与数据库出现偏差时,运维人员需要明确的指标和告警来感知异常,否则系统处于“盲飞”状态。
- 架构演进基础:微服务、CQRS、事件驱动等架构都依赖缓存一致性作为数据同步的基石,不一致会破坏整个架构的信任模型。
⚠️ 常见误区:很多团队认为“缓存只是加速,不一致没关系”。实际上,一旦缓存数据被下游服务或用户用于决策,不一致就会产生连锁错误。缓存一致性不是性能的敌人,而是正确性的盟友。
1.3 缓存与数据库数据不一致的典型场景
在实际生产环境中,缓存不一致几乎无法完全避免。以下是最常见的 5 类场景,也是本课程后续章节要重点解决的痛点:
| # | 场景名称 | 触发条件 | 不一致表现 | 影响等级 |
|---|---|---|---|---|
| 1 | 先删缓存后写库 | 并发读请求在缓存删除后、数据库写入前命中 | 读到旧数据写入缓存,覆盖新数据 | 高 |
| 2 | 先写库后删缓存失败 | 数据库写入成功,但删除缓存操作因网络/超时失败 | 缓存长期保留旧数据 | 高 |
| 3 | 异步任务延迟 | 异步 binlog 消费或 MQ 消息积压 | 缓存更新滞后于数据库变更 | 中 |
| 4 | 主从延迟 + 缓存穿透 | 写主库后立即读从库,从库尚未同步 | 缓存写入的是从库旧数据 | 中 |
| 5 | 缓存 TTL 过期 + 并发回源 | 多个请求同时发现缓存过期,同时回源数据库 | 缓存击穿,数据库压力激增,数据错乱 | 高 |
1.4 一致性问题的本质
从分布式系统理论角度看,缓存一致性问题的本质是读写并发 + 网络不可靠 + 操作非原子三个因素的叠加:
- 读写并发:多个线程/进程同时对缓存和数据库进行操作,时序交错导致竞态条件。
- 网络不可靠:删除缓存或写入数据库的操作可能超时、重试、乱序,破坏预期顺序。
- 操作非原子:“先删缓存后写库”或“先写库后删缓存”都不是原子操作,中间状态暴露给并发请求。
💡 课程视角:本课程将围绕“异步任务”这一核心手段,系统性地解决上述三类问题。异步任务不是万能的,但结合消息队列、binlog 监听、补偿机制和监控告警,可以构建一套高可用的缓存一致性保障体系。