2026/1/9 12:28:00
网站建设
项目流程
美食网站素材,网站编辑做图片用什么不同,中铁建设集团门户网app,咸阳seo优化在后端面试中#xff0c;只要简历上写了 Redis#xff0c;这道题是100% 必问的#xff1a; “怎么保证缓存和数据库的数据一致性#xff1f;” 因为在生产环境中#xff0c;细节才是魔鬼。今天我们就从“青铜”到“王者”#xff0c;拆解 4 种方案#xff0c;并揭秘3 个…在后端面试中只要简历上写了 Redis这道题是100% 必问的“怎么保证缓存和数据库的数据一致性”因为在生产环境中细节才是魔鬼。今天我们就从“青铜”到“王者”拆解 4 种方案并揭秘3 个连老鸟都容易踩的致命误区。❌ 方案1先删缓存再更新 DB青铜这是很多新手的直觉反应“先把旧缓存清了再改数据库下次读的时候不就读到新的了吗”错这是个巨大的坑。只要你的系统有一点并发量这个方案就是个 Bug 制造机。翻车现场还原看看下面这个时序图你就知道为什么不能用了结局MySQL 是新的Redis 是旧的。而且因为 Redis 里有数据后续请求都不会去查库这个脏数据会一直存在直到过期。✅ 方案2先更新 DB再删缓存黄金 - Cache Aside这是业界最常用的Cache Aside Pattern。逻辑先更新 MySQL。更新成功后删除 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);}方案4Canal 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 也是白搭。记住延迟双删只能降低不一致概率无法根除。总结一张表互动话题你在生产环境中用的是哪种方案有没有踩过“事务内删缓存”的坑欢迎在评论区聊聊你的“血泪史”