缓存(Cache)是一种计算机存储技术,用于提高数据访问速度。它通过将频繁访问的数据存储在快速访问的存储介质中,以减少对主存储器(如硬盘)的访问次数,从而提高整个系统的性能。### 缓存的基本概念1. **存储介质**:缓存通常使用比主存储器(如RAM)更

摘要:这是后端面试必考、工程必踩的核心问题:更新数据库时,怎么保证缓存里的数据是对的? 我给你讲得原理通透、方案落地、能直接写进架构文档。 一、先搞懂:为什么会不一致? 本质只有一句话: 缓存和数据库是两个独立存储,无法原子更新。 只要是「先操作
这是后端面试必考、工程必踩的核心问题:更新数据库时,怎么保证缓存里的数据是对的? 我给你讲得原理通透、方案落地、能直接写进架构文档。 一、先搞懂:为什么会不一致? 本质只有一句话: 缓存和数据库是两个独立存储,无法原子更新。 只要是「先操作A,再操作B」两步动作,就一定可能出现: 第一步成功 第二步失败/超时/延迟 → 数据不一致 常见脏数据场景: 线程1更新DB → 还没删缓存 线程2读缓存 → 读到旧数据 线程1才删缓存 → 业务读到脏数据 二、最关键结论(先记死) 所有正确方案,都遵守一条铁律: 写数据时,一定是「更新数据库 + 淘汰缓存」,绝对不能「更新数据库 + 更新缓存」。 原因: 更新缓存 = 写放大,高并发下浪费CPU 并发更新会产生覆盖,导致永久脏数据 三、四种经典策略(原理+优缺点+场景) 1)Cache Aside Pattern(最常用、业务主流) 流程 读:命中直接返回,不命中读DB → 回填缓存 写:更新DB → 删除缓存 为什么是删除,不是更新? 因为: 你不知道这次更新后,有没有人会读 不读就不需要写缓存 写缓存=无效开销 可能问题 更新DB后,删除缓存失败 → 脏数据 适用 90% 业务系统、订单、用户、商品等。 2)Write Through(写穿透) 流程 DB 和缓存 同步更新,一起成功/失败 需要强事务支持,Redis本身不支持。 问题 性能差,几乎不用。 3)Write Behind(异步写) 流程 写缓存 → 立即返回 → 异步刷DB 问题 丢数据风险极大,不适合金融/订单核心链路。 4)Read Through(读穿透) 由缓存组件自己负责读DB,业务不关心。 常见于框架,不常用。 四、真正核心:先更DB?还是先删缓存? 这是面试必考题。 错误方案:先删缓存,再更新DB 一定会产生脏数据: 线程1删缓存 线程2读DB → 旧数据 → 写入缓存 线程1更新DB → 缓存旧,DB新,永久不一致 正确方案:先更新DB,再删缓存 这是业界标准正确姿势。 五、先更新DB、再删缓存,还有问题吗? 有!极端并发下会短暂不一致。 极端场景(概率极低) 线程A读:缓存不命中 → 读DB旧值 线程B写:更新DB新值 → 删除缓存 线程A把旧值写回缓存 → 缓存脏了 结论 概率极低 是短暂不一致,不是永久脏数据 对绝大多数业务可接受 六、工业级一致性方案(能落地的) 方案1:延迟双删(简单实用) 流程: 更新DB 删除缓存 延迟几百ms,再删一次 作用: 把刚才那种极端并发写入的旧缓存删掉。 优点:简单、稳定、99%场景够用。 方案2:删除缓存重试机制(高可靠) 删除缓存失败怎么办? MQ重试 定时任务重试 分布式任务重试 保证:最终一定能删掉。 方案3:Canal/订阅binlog异步淘汰(最稳) 流程: 业务只写DB Canal订阅binlog 解析到更新 → 异步删除缓存 优点: 业务无侵入 一致性最强 高并发下最稳 大厂主流方案。 七、最终一致性 vs 强一致性 Redis + DB 只能保证: 最终一致性 强一致性怎么做? 2PC(性能差) TCC(复杂) Paxos/Raft(太重) 缓存场景几乎不用 八、最清晰总结(面试直接背) 缓存不一致根源:DB与缓存无法原子更新 正确写策略:先更新DB,再删除缓存 绝对不能:先删缓存,再更DB 绝对不能:更新缓存,只能删除 高一致推荐:Canal binlog异步淘汰 简单可靠:延迟双删 缓存+DB只能做到最终一致 一句话: 更新数据库,删除缓存,最终一致。