Redis和MySQL如何保证数据一致性

先搞懂问题本质

为什么会有「数据一致性」问题?

因为我们系统里同时存在两个”仓库”:

仓库 特点 类比
MySQL 持久化,数据不丢,但慢 正式仓库(在郊区)
Redis 内存存储,超快,但断电丢数据 前台展示柜(在门口)

用户来买东西,先看展示柜(Redis),有货直接拿走,快!

展示柜没货,才去正式仓库(MySQL)取,慢但可靠。

问题来了:展示柜的货和仓库的货,怎么保持一致?


经典场景:下单扣库存

假设你在电商平台买了最后一件商品:

// 伪代码:下单流程
1. 查询库存 → 先查Redis(快)
2. 库存 > 0 → 允许下单
3. 扣减库存 → 先更新MySQL(持久化)
4. 删除/更新Redis缓存

听起来很合理?但魔鬼藏在细节里 👇


四大经典坑

💣 坑一:先更新数据库,再删缓存(最常见方案)

线程A:更新MySQL库存 = 99
线程A:删除Redis缓存
线程B:查询Redis(缓存已删)→ 查MySQL → 写入Redis = 99
✅ 正常情况:没问题

但如果这样呢:

线程A:更新MySQL库存 = 99
线程A:删除Redis缓存 ← 此时宕机!
结果:MySQL=99,Redis=100(旧数据)
💥 数据不一致!

🐟 比喻:仓库已经卖出一件,但展示柜忘记更新,顾客看到的还是旧数量。

💣 坑二:先删缓存,再更新数据库

线程A:删除Redis缓存
线程B:查询Redis(缓存不存在)→ 查MySQL(旧值100)→ 写入Redis=100
线程A:更新MySQL库存 = 99
结果:MySQL=99,Redis=100
💥 更惨!

🐟 比喻:展示柜刚清空,还没来得及从仓库补货,另一个员工又把旧数量填回去了。

💣 坑三:双写(同时更新MySQL和Redis)

线程A:更新MySQL=99,更新Redis=99
线程B:更新MySQL=98,更新Redis=98
// 如果顺序错乱:
线程A先写MySQL,线程B先写Redis
结果:MySQL=98,Redis=99
💥 又不一致!

💣 坑四:缓存击穿 + 并发写

高并发下,缓存刚删除的瞬间,大量请求同时打到MySQL,然后同时往Redis写,写入顺序不保证,最终结果随机。

🐟 比喻:展示柜空了,100个顾客同时冲进仓库,每人拿了一个数字往展示柜上贴,最后贴上去的是哪个数谁也不知道。

 


主流解决方案

✅ 方案一:Cache Aside(旁路缓存)—— 最常用

口诀:读的时候加缓存,写的时候删缓存

读操作:
  1. 查Redis → 有则返回
  2. 没有 → 查MySQL → 写入Redis → 返回

写操作:
  1. 更新MySQL
  2. 删除Redis缓存(不是更新!)

为什么是删除而不是更新缓存?

因为更新缓存在并发下容易写入旧值,删除更安全——下次读的时候自然会从MySQL重新加载最新值。

✅ 方案二:延迟双删 —— 解决并发问题

1. 删除Redis缓存
2. 更新MySQL
3. 睡眠500ms(等其他线程的读操作完成)
4. 再次删除Redis缓存

第二次删除是为了清掉步骤1-2之间可能被其他线程写入的旧缓存。

🐟 比喻:展示柜清空 → 更新仓库 → 等所有顾客都看完 → 再清一次展示柜,确保没有旧数据残留。

✅ 方案三:消息队列 + 异步更新 —— 高可靠

更新MySQL → 发消息到MQ → 消费者异步删除/更新Redis

优点:解耦,即使Redis删除失败,MQ会重试。

缺点:有短暂的不一致窗口(最终一致性)。

✅ 方案四:Canal监听binlog —— 终极方案

MySQL binlog → Canal → 消息队列 → 删除Redis

Canal 是阿里开源的 MySQL binlog 监听工具,MySQL 数据一变,Canal 立刻感知,自动同步到 Redis。

🐟 比喻:仓库装了监控摄像头(Canal),一旦货物有变动,自动通知展示柜更新,完全自动化,人工不介入。


面试怎么答?

面试官问这个问题,其实想考察你三点:

考察点 你应该说
问题意识 先说清楚为什么会不一致(并发、宕机)
方案掌握 Cache Aside → 延迟双删 → MQ → Canal,按复杂度递进
业务判断 根据一致性要求选方案(强一致 vs 最终一致)

标准答案模板:

「Redis和MySQL的一致性问题,核心是写操作时的缓存处理策略。我们通常采用Cache Aside模式:读时加缓存,写时删缓存而非更新缓存。对于高并发场景,可以加延迟双删来降低脏数据概率。如果对一致性要求更高,可以引入消息队列做异步补偿,或者用Canal监听MySQL binlog来实现自动同步。具体选哪种,要看业务对一致性的容忍度。」

给TA打赏
共{{data.count}}人
人已打赏
MySQL

PXC集群部署

2024-5-4 15:31:53

Docker

Centos7离线安装Docker

2022-4-17 23:24:27

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索