[Redis小技巧20]先删缓存还是先更新数据库?一文厘清 Redis 缓存一致性难题
在现代分布式系统中Redis 几乎已成为缓存层的“标配”。然而缓存与数据库之间的一致性问题始终是高并发场景下的“阿喀琉斯之踵”。一、为什么缓存一致性如此棘手缓存一致性问题的本质源于写操作在缓存与数据库之间的非原子性。当多个线程/服务同时读写时可能出现以下典型异常脏读读到旧缓存数据数据库已更新缓存未失效幻读缓存刚被删除另一个请求回种了旧值雪崩写入缓存失效瞬间大量请求穿透到 DB这些问题在秒杀、订单、库存等强一致性场景中尤为致命。二、主流缓存一致性方案详解1. Cache-Aside缓存分离模式 —— 行业默认方案这是最广泛采用的模式其读写流程如下读先查缓存 → 未命中则查 DB → 回填缓存写先更新 DB → 再删除缓存注意不是更新缓存优势简单、通用、避免缓存与 DB 写放大风险若“删缓存”失败将导致长时间不一致Cache-Aside 写流程关键点先更新 DB再删缓存。若反过来先删缓存再更新 DB在并发场景下极易出现“旧值回种”问题。2. “先删缓存再更新 DB” —— 为何是反模式假设有两个并发请求请求 A先删缓存请求 B读缓存miss→ 读 DB旧值→ 回种缓存请求 A更新 DB新值结果缓存中存的是旧值DB 是新值 → 不一致此方案在高并发下几乎必然失败强烈不推荐。3. 双删Double Delete策略为缓解“旧值回种”可在写操作中执行两次删除1. 删除缓存 2. 更新数据库 3. 延迟 N 毫秒后再次删除缓存第二次删除旨在清除步骤 2 期间可能被并发读请求回种的旧值。优点比单删更可靠缺点引入延迟、仍不能 100% 保证一致若第二次删失败或延迟不足双删失败案例展示1场景设定缓存键user:1001初始值{name: Alice, balance: 100}有两个并发操作同时发生写请求 W将余额更新为 200使用“双删”策略读请求 R在 W 执行过程中发起读取2详细时序展示“双删”失败的情况时间点操作状态T0W 开始第一次删除缓存(DEL user:1001)缓存为空T1R 发起读缓存 → miss—T2R 继续读数据库 → 得到旧值balance100DB 尚未更新T3W 继续更新数据库 →balance200DB 已更新T4R 继续将旧值balance100回种到缓存❌ 缓存被污染T5W 等待 N 毫秒比如 500ms后第二次删除缓存缓存再次被清空T6另一个读请求 R2缓存 miss → 读 DB → 得到200→ 回种正确值✅ 恢复正常问题出在哪里在T4 到 T5 之间缓存中存储的是错误的旧值100。如果在这段时间内有其他读请求比如 T4.5它们会读到脏数据。更糟的是如果第二次删除因网络超时、Redis 故障或程序异常而失败这个错误值可能长期驻留缓存3极端但真实的失败案例假设系统延迟波动大如 GC 停顿、网络抖动设置的“N 500ms”可能不够数据库主从同步延迟 800ms某个读请求从从库读到了旧值因为主从未同步完成它在 T4 回种了旧值而你的双删只等了 500ms第二次删除发生在主从同步完成前此时Redis缓存读到的依然是旧数据结果缓存长期不一致4如何缓解——但无法根治增大延迟时间 N如 1–2 秒→ 但牺牲响应速度用户体验下降第二次删除失败时重试如最多 3 次→ 增加复杂度结合 Binlog 监听如用 Canal自动失效缓存 → 转向更可靠的“订阅变更”模式但请注意只要删除操作是“尽力而为”best-effort就无法提供强一致性保证。4. 延时双删Delayed Double Delete这是双删的增强版通常配合消息队列实现第一次删缓存同步更新 DB发送延迟消息如 RabbitMQ / RocketMQ 延迟队列消费者在 1–2 秒后执行第二次删除优势解耦、可重试、避免阻塞主流程成本需引入 MQ系统复杂度上升5. 其他方案简述方案原理适用场景一致性强度Read/Write Through缓存层代理所有读写自动同步 DB封闭系统、中间件可控强Write Behind Caching先写缓存异步批量刷 DB日志、监控等容忍丢失场景弱版本号/逻辑时钟缓存与 DB 带版本读时校验极高一致性要求如金融强注Redis 本身不支持 Write Through需应用层或代理层实现如 Twemproxy 自定义逻辑。三、方案对比总表方案是否推荐并发安全性实现复杂度最终一致性典型应用场景先删缓存后更新 DB❌ 否低低❌ 差—Cache-Aside删缓存更新DB✅ 是中低✅ 可接受通用 Web 应用双删⚠️ 谨慎中高中✅ 较好订单、库存延时双删✅ 推荐高并发高高✅ 优电商、支付Read/Write Through✅若架构支持高高✅ 强金融核心系统四、高频面试题Q1为什么 Cache-Aside 模式要“先更新 DB再删缓存”答若先删缓存DB 更新前若有并发读请求会将旧值重新加载到缓存导致后续读取到脏数据。先更新 DB 可确保即使缓存 miss读到的也是最新值。Q2双删一定能解决一致性问题吗答不能 100% 保证。若第二次删除失败或延迟时间不足以覆盖所有并发读仍可能不一致。需配合重试、告警、监控机制。Q3如何监控缓存一致性问题答可通过以下方式记录缓存命中率突降对比 DB 与缓存的关键字段抽样校验使用 Redis 的MONITOR仅调试或审计日志在业务层埋点记录“缓存版本 vs DB 版本”Q4能否用 Redis 事务MULTI/EXEC保证一致性答不能。Redis 事务不支持回滚且无法跨 DB 与缓存原子操作。缓存一致性本质是分布式事务问题需更高层协调。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2429761.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!