缓存数据库一致性的问题整理

63 阅读3分钟

以下是  “问题场景 → 最优解决方案”  的直接对应表,不用纠结复杂理论,遇到对应问题直接选方案,清晰落地:

核心问题场景最优解决方案核心做法关键说明(避坑 + 兜底)
1. 读多写少、数据低频变更(如商品详情、秒杀库存查询),想提升接口吞吐量、减轻数据库压力缓存热点数据(Cache Aside 模式)① 查询:先查缓存,命中直接返回;未命中查数据库,写入缓存后返回② 写操作:后续配合 “删缓存” 方案基础方案,必须给缓存设过期时间(兜底防脏数据),适合无强一致性要求的场景
2. 需保证缓存与数据库最终一致,不想写复杂代码(大多数常规业务场景)先更新数据库,再删除缓存写操作时:先修改数据库数据 → 数据库更新成功后,删除对应缓存脏数据概率极低(数据库读比写快),实现最简单,无业务侵入,搭配缓存过期时间兜底
3. 并发极高,用 “先删缓存再更数据库” 时,出现 “查询旧数据写入缓存” 的脏数据延时双删① 先删除缓存② 更新数据库③ 异步休眠(预估读业务耗时 + 300~500ms)后,再次删除缓存解决并发读写冲突,休眠时间要适配业务:- 普通场景:读业务耗时 + 500ms- 读写分离场景:主从同步延时 + 读耗时 + 500ms用线程池异步执行,避免阻塞用户请求
4. 删除缓存失败(如网络波动、缓存集群故障),导致脏数据残留删除缓存重试机制(优先选 Canal 订阅 binlog)方案 1(无侵入):① 数据库更新后写入 binlog② Canal 订阅 binlog,解析出变更数据的 key③ 异步删除缓存,失败则存入消息队列重试方案 2(简单侵入):删缓存失败后,直接将 key 丢进消息队列重试方案 1 更优(不污染业务代码),依赖 Canal + 消息队列,确保删除操作 “最终成功”
5. 写操作频繁、或更新缓存需复杂计算(如多表统计),更新缓存性价比低直接删除缓存,不更新缓存写操作时只删缓存,不做任何更新;下次查询自动从数据库加载最新数据到缓存避免无效计算和频繁更新缓存,减少一致性风险,是通用推荐的写缓存策略
6. 用 MySQL 读写分离(主写从读),主从同步有延时,导致从库旧数据写入缓存延时双删(调整休眠时间)同 “延时双删”,但休眠时间 = 主从同步延时(如 1~2s)+ 读业务耗时 + 500ms等主从数据同步完成后再删缓存,避免从库旧数据被写入缓存
7. 高一致性要求(如金融、订单核心数据),需最小化脏数据时间窗口延时双删 + 缓存重试机制 + 缓存过期时间① 写操作走 “延时双删”② 删缓存失败触发 Canal + 消息队列重试③ 缓存设短过期时间(如 5~10 分钟)无绝对一致性方案,此组合是 “最终一致性” 的最优实践,最大化降低脏数据概率

最后 3 个关键兜底提醒(必看):

  1. 所有方案都要给缓存设 过期时间(哪怕是 1 小时),这是极端情况下的最后保障,防止脏数据永久残留;
  2. 不要用 “先更新缓存再更新数据库” 的方案,线程安全问题严重,脏数据概率极高;
  3. 秒杀等超高并发场景,优先用 “缓存热点数据 + 先更数据库再删缓存 + 过期时间”,足够支撑业务,无需过度设计。