news 2026/4/15 14:51:52

Mysql和Redis双写不一致问题怎么解决?—— 别让 300ms 的延迟毁了你的数据

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Mysql和Redis双写不一致问题怎么解决?—— 别让 300ms 的延迟毁了你的数据

在后端面试中,只要简历上写了 Redis,这道题是100% 必问的:

“怎么保证缓存和数据库的数据一致性?”

因为在生产环境中,细节才是魔鬼。今天我们就从“青铜”到“王者”,拆解 4 种方案,并揭秘3 个连老鸟都容易踩的致命误区


❌ 方案1:先删缓存,再更新 DB(青铜)

这是很多新手的直觉反应:“先把旧缓存清了,再改数据库,下次读的时候不就读到新的了吗?”

错!这是个巨大的坑。只要你的系统有一点并发量,这个方案就是个 Bug 制造机。

翻车现场还原

看看下面这个时序图,你就知道为什么不能用了:

结局:MySQL 是新的,Redis 是旧的。而且因为 Redis 里有数据,后续请求都不会去查库,这个脏数据会一直存在,直到过期。


✅ 方案2:先更新 DB,再删缓存(黄金 - Cache Aside)

这是业界最常用的Cache Aside Pattern

逻辑

  1. 先更新 MySQL。

  2. 更新成功后,删除 Redis 缓存。

为什么这个比方案 1 好?
虽然理论上它也存在并发问题,但在实际生产中,这种情况发生的概率极低
因为“数据库写操作”通常比“缓存读写”慢得多。要触发 Bug,需要读请求在“写请求更新完 DB 但还没删缓存”的极短微秒级时间窗口内完成整个操作,这需要极其巧合的时间差。

适用场景:90% 的读多写少业务。


✅ 方案3:延迟双删(钻石 - 高并发优化)

如果你无法容忍方案 2 中那“万分之一”的概率,或者你的数据库主从延迟比较大,延迟双删是性价比最高的方案。

核心逻辑
先删缓存 -> 更新 DB -> 休眠 N 毫秒 -> 再删缓存

为什么要删两次?

  • 第一次删:为了腾地儿。

  • 第二次删:为了把“在更新 DB 期间,其他读请求可能写入的脏数据”给清理掉。

生产级代码实现

这里有个细节:休眠时间怎么定?

经验公式:Sleep 时间 ≈ (主从同步延迟 + 读请求平均耗时) * 1.5
一般设置为 300ms - 500ms。

publicvoidupdateUser(Useruser) { Stringkey ="user:"+ user.getId(); // 1. 第一次删除 redisTemplate.delete(key); // 2. 更新数据库 userMapper.updateById(user); // 3. 异步延迟第二次删除 (防止阻塞主线程) CompletableFuture.runAsync(() -> { try{ Thread.sleep(500);// 关键:给主从同步留出时间 redisTemplate.delete(key); }catch(InterruptedExceptione) { e.printStackTrace(); } }, executor);}


方案4:Canal + MQ(王者 - 金融级一致性)

如果你做的是金融、支付业务,连“应用层删缓存失败”都不能容忍,那就必须把应用层解耦。

原理:应用层只管写 MySQL,由 Canal 伪装成 MySQL Slave 监听 Binlog,投递到 MQ,消费者负责删缓存并自动重试

深度思考:金融业务的“双标策略”

很多人问:“Canal 也有延迟,金融业务怎么能忍?”
这里有一个认知误区。真实的金融架构采用了双标策略

结论:Canal + MQ 保证的是“展示链路”的数据最终一定是正确的,不会出现“删缓存失败”导致的永久脏数据。


避坑指南:3 个让你背 P0 事故的“隐形误区”

方案选对了就稳了吗?下面这三个坑,踩中一个就是生产事故。

误区 1:在事务(@Transactional)里面删缓存

这是 Spring 开发中最容易犯的低级错误!

❌ 错误代码

@TransactionalpublicvoidupdateUser(Useruser) { userMapper.updateById(user); // MySQL 还没 Commit! redisTemplate.delete("user:1"); // Redis 先删了 // ... 方法结束,事务才 Commit}

后果:Redis 删了,DB 还没提交。读请求进来读到旧值写回 Redis,随后事务提交。Redis 永远是旧值。

✅ 修正方案:利用事务同步管理器

publicvoidupdateUser(Useruser) { userMapper.updateById(user); // 注册一个回调,确保事务提交成功后再删缓存 TransactionSynchronizationManager.registerSynchronization( newTransactionSynchronization() { @Override publicvoidafterCommit() { redisTemplate.delete("user:"+ user.getId()); } } );}

误区 2:针对“热点 Key”直接删缓存

对于微博热搜、秒杀库存这种Top Hot Key千万不能直接删!
删掉缓存的瞬间,几万个请求会直接击穿到 MySQL,数据库瞬间 CPU 100% 宕机。

✅ 修正
针对超热点 Key,使用双写更新(允许短暂不一致)或分布式锁(只放一个线程回写)。

误区 3:迷信延迟双删的 Sleep 时间

Sleep(500ms) 只是一个经验值。如果网络抖动,主从延迟飙升到 1 秒,你睡 500ms 也是白搭。
记住:延迟双删只能降低不一致概率,无法根除


总结一张表


互动话题

你在生产环境中用的是哪种方案?有没有踩过“事务内删缓存”的坑?欢迎在评论区聊聊你的“血泪史”!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 4:08:01

Open-AutoGLM部署难题全解析,一文解决99%常见错误

第一章:Open-AutoGLM开源实操指南环境准备与项目克隆 在开始使用 Open-AutoGLM 前,需确保本地已安装 Python 3.9 和 Git。推荐使用虚拟环境以隔离依赖。创建虚拟环境:python -m venv open-autoglm-env激活环境(Linux/macOS&#x…

作者头像 李华
网站建设 2026/4/14 18:56:15

2025最新!专科生必备9个AI论文平台测评与推荐

2025最新!专科生必备9个AI论文平台测评与推荐 2025年专科生论文写作工具测评:为何需要一份精准指南? 随着人工智能技术的快速发展,AI论文平台逐渐成为高校学生,尤其是专科生群体的重要辅助工具。然而,面对市…

作者头像 李华
网站建设 2026/4/14 14:11:12

Open-AutoGLM部署实战(千卡级优化秘籍)

第一章:Open-AutoGLM部署实战(千卡级优化秘籍)在超大规模模型训练场景中,Open-AutoGLM 的千卡级集群部署对性能调优提出了极高要求。合理的资源配置与通信优化策略是实现线性加速比的关键。分布式训练架构设计 采用混合并行策略&a…

作者头像 李华
网站建设 2026/4/15 9:46:46

【AI自动化工具下载指南】:智普Open-AutoGLM获取路径全解析

第一章:智普Open-AutoGLM如何下载 访问官方仓库 智普AI推出的Open-AutoGLM是一个开源的自动化代码生成工具,其源码托管在GitHub平台。用户需首先访问项目主页以获取最新版本的下载链接。 打开浏览器,访问 https://github.com/zhipuai/Open-…

作者头像 李华
网站建设 2026/4/8 16:11:49

模型部署效率提升300%?Open-AutoGLM轻量化配置秘籍曝光

第一章:模型部署效率提升300%?Open-AutoGLM轻量化之谜在大模型时代,推理延迟与资源消耗成为制约AI落地的关键瓶颈。Open-AutoGLM作为开源社区新兴的轻量化自动推理框架,凭借其独特的模型压缩策略与运行时优化机制,宣称…

作者头像 李华
网站建设 2026/4/10 12:43:31

RAG架构演进全解析:从基础到智能化的四代架构之路

本文系统梳理了RAG架构从基础到智能化的四代演进历程,详细分析了Naive、Advanced、Modular和Agentic RAG的核心特点与技术突破。文章展示了RAG如何通过模块化设计、智能体协同解决知识更新、语义对齐和复杂任务处理等问题,为LLM应用落地提供架构参考&…

作者头像 李华