← 返回首页

redis与数据库的缓存一致性

在分布式系统中,Redis(缓存)与 MySQL(数据库)的数据一致性是后端开发的核心难点。由于两者是独立的存储组件,数据更新无法做到绝对的原子性,因此极易产生不一致。

解决该问题没有“银弹”,核心原则是:数据库始终是“唯一数据源”,缓存仅作为加速读取的临时空间。以下为您系统梳理从基础到进阶的几种主流解决方案:

一、 业界首选通用方案:Cache-Aside 模式

核心策略:先更新数据库,再删除缓存

这是目前最常用、平衡了性能与一致性的最优解。

  • 读流程:先查 Redis,若命中则直接返回;若未命中,查询 MySQL,将结果写入 Redis(并设置过期时间)后返回。
  • 写流程:先更新 MySQL 确保底层数据最新,然后删除 Redis 中对应的 Key。后续读取时会自动从 DB 加载最新数据并重建缓存。
  • 为什么是“删”而不是“更新”?:删除操作天然幂等,能避免并发更新时“旧值覆盖新值”的脏数据问题;同时对于冷数据,避免了无效的缓存写入浪费资源。

二、 进阶优化方案

针对 Cache-Aside 模式在极端并发下可能出现的短暂不一致,可采用以下进阶手段:

  1. 延迟双删策略

    • 原理:在更新数据库后,先删除一次缓存,休眠一段时间(如 500ms),再次删除缓存。休眠时间需大于“查询数据库+写入缓存”的最大耗时,目的是把并发读请求可能回填的旧数据彻底清除。
    • 适用场景:业务强制要求使用“先删缓存”流程,或对一致性要求稍高的读多写少场景。
    • 缺点:线程休眠会阻塞请求导致接口性能下降,且延迟时间难以精准适配所有网络环境。
  2. 消息队列异步重试

    • 原理:将删除缓存的操作封装成消息发送到 MQ(如 RocketMQ、Kafka)。消费者监听到消息后执行删除,若失败则自动重试。这保证了删除操作至少被执行一次,大幅提高了可靠性。

三、 强一致性终极方案:订阅 Binlog

核心策略:基于 Binlog 异步更新缓存

适用于金融、支付、订单等对数据一致性要求极高(零容忍脏数据)的核心业务。

  • 原理:业务代码只负责操作数据库,完全不触碰缓存。利用 Canal 等中间件伪装成 MySQL 从节点,实时监听并解析 Binlog 日志,提取变更数据后投递到 MQ,最终由消费服务更新/删除 Redis 缓存。
  • 优势:做到了业务零侵入和逻辑解耦,依靠 MQ 削峰填谷,支持重试与故障恢复,稳定性极高。
  • 缺点:架构复杂度高,需要额外维护 Canal、MQ 等中间件,运维成本较大。

四、 强一致兜底与避坑指南

  1. 设置合理的 TTL(过期时间):这是所有方案的必备兜底机制。即使上述同步操作全部失败,只要 TTL 到期,缓存也会自动失效并从数据库加载最新数据,保证最终一致性。
  2. 绝对不推荐的方案:“先更新缓存,再更新数据库”。在高并发下,后提交的数据库请求可能先完成缓存更新,导致新数据被旧数据永久覆盖。
  3. 高并发防脏写:可在数据库层面引入乐观锁(通过 version 版本号字段),防止并发更新时的数据覆盖冲突。

 方案选型总结建议

  • 绝大多数普通业务:优先选择 “先更库,再删缓存” + TTL 兜底。实现简单、性能最优。
  • 对一致性要求稍高:采用 Cache-Aside + 延迟双删 / MQ异步重试。
  • 金融/交易等核心业务:采用 Canal 订阅 Binlog 方案,以架构复杂度换取极致的可靠性。