1022 字
约 3 分钟
10
S11-A03 · MySQL → ES / 缓存一致性
适用读者:要做"数据库 + 搜索/缓存"双写的人。
前置:S11-J05。
覆盖旧文:2686(141) 2690(141) 2666(84) 1732(79) = 445 点。
覆盖扩展:E-S11-009(三方案对比)。
上一篇:S11-A02 · 部署与迁移:Docker 跑 MySQL、Flyway
下一篇:S11-X01 · 八股速查。
1. 一句话结论
"数据库 + 另一个存储"的一致性只有三种路线:双写、订阅 binlog、定时对账。它们的差别在"延迟、侵入性、可靠性"。
| 方案 | 延迟 | 侵入性 | 可靠性 |
|---|---|---|---|
| 双写(应用里同时写两边) | 低 | 高(业务代码要管) | 差(一边失败就脏) |
| binlog 订阅 / CDC | 中(秒级) | 低(对应用透明) | 好(可回溯) |
| 定时对账 | 高(分钟+) | 低 | 兜底用,不做主路径 |
2. 双写为什么不推荐(E-S11-009)
① 写 MySQL 成功 → ② 写 ES 失败 → 数据不一致
① 写 MySQL 失败 → ② 写 ES 成功 → 脏数据
| 补救 | 效果 |
|---|---|
| 加重试 | 只能缓解,最终一致仍可能失败 |
| 加事务消息 | 引入 MQ,复杂度上升 |
| 失败落表 + 补偿任务 | 可行,但等于自己写了个 CDC |
判据:"能接受双写的不一致窗口吗?" 不能 → 别用双写做主路径。
3. binlog 订阅(推荐)
| 组件 | 说明 |
|---|---|
| Canal / Debezium / Maxwell | 伪装成从库读取 binlog |
| 消息队列 | 缓冲与解耦 |
| 消费端 | 写 ES / 更新业务 |
前提:binlog_format=ROW(必须)、binlog_row_image=FULL(推荐)、有权限。
优势:应用无侵入、可回溯、断点续传。
代价:多一套组件、需要监控消费延迟。
4. 缓存一致性:先删缓存还是先更库(A-1732)
| 方案 | 问题 |
|---|---|
| 先更库、后删缓存 | 并发下仍可能读到旧值(窗口小) |
| 先删缓存、后更库 | 窗口更大(容易读到旧值) |
| 延迟双删 | 更库前后各删一次,缓解 |
| 订阅 binlog 删缓存 | 最彻底(与 §3 同源) |
判据:"缓存里的旧值能存在多久?" 要求"秒级以下" → binlog 驱动;容忍几十毫秒 → 延迟双删够用。
"cache-aside 的经典竞态":读线程先读库、再写缓存;写线程中途删缓存 → 缓存里留下旧值。根本解法只有"让失效消息来自数据变更本身"(binlog)。
5. 迁移与验收
| 阶段 | 动作 |
|---|---|
| 双写期 | 主写 MySQL,旁路写 ES(观察差异) |
| 切换期 | 读切 ES(灰度 1%→100%) |
| 收口 | 关掉旁路双写,改 binlog 订阅 |
| 对账 | 定时全量/增量比对(兜底) |
验收指标:同步延迟 P99、差异条数、消费积压。
6. 五个误区
| 误区 | 真相 |
|---|---|
| "双写最简单" | 不一致窗口最大 |
| "binlog 订阅没有延迟" | 秒级延迟仍存在 |
| "缓存删除顺序决定一切" | 竞态窗口存在,最终要靠数据变更驱动 |
| "对账能做主路径" | 只能兜底 |
| "ES 能替代数据库" | 不是事务型存储 |
7. 自检(架构师版)
- 三种同步方案的延迟/侵入性/可靠性对比?
- 双写为什么"失败即脏"?
- binlog 订阅的三个前提?
- 缓存一致性的根本解法是什么?
- 迁移的四阶段与验收指标?
8. 下一篇
S11-X01 · MySQL 八股速查
最后一篇是附录索引:83 道 MySQL 八股压成"题 → 一句话答案 → 正文位置"。
本篇属于系列《S11 · 数据库与 SQL》。旧文来源:A-2686/2690/2666/1732;扩展点 E-S11-009。
S11-A03 · MySQL → ES / 缓存一致性
https://www.clxhxhhr.top/posts/5341/ 评论
0 条
还没有评论,先写一条吧。