最后更新:2026-11-01 · 基于第 1 次作答
结论:缓存一致性本质是"数据更新后缓存未同步"的中间态,方案按一致性强度递进——TTL 兜底最终一致 → Cache Aside 删缓存 → 延迟双删 → binlog 订阅删除 → 读后回填。 关键词:Cache Aside · 延迟双删 · binlog 订阅 边界:强一致需写库后失效并控制并发读写顺序;"删缓存"比"更新缓存"更稳。
核心考点定位:考察缓存一致性问题的根因(更新顺序 + 并发读写竞态)与多级方案取舍;面试官想看到"先分析不一致怎么产生,再给方案",而非只背"先更库再删缓存"。
机制链(≥3 环):
500ms)删一次 → 旧值回填在第二次删除时被清掉。证据锚点:
Cache Aside:读未命中回填、写后删缓存TTL:兜底最终一致500ms:常见延迟窗口量级binlog:DB 变更日志Canal:MySQL binlog 订阅组件cache-aside / read-through / write-through / write-back:四种缓存模式Redis:缓存存储MYSQL:数据源(主从延迟影响一致性窗口)对比与权衡:
| 方案 | 一致性 | 复杂度 | 实时性 | 适用 |
|---|---|---|---|---|
| TTL 兜底 | 最终一致 | 低 | 有延迟 | 可容忍不一致 |
| Cache Aside 删缓存 | 最终一致 | 低 | 高 | 常规 |
| 延迟双删 | 最终一致(更强) | 中 | 高 | 高并发写 |
| binlog 订阅 | 最终一致(可靠) | 高 | 高 | 复杂/强依赖 |
| 读后回填 | 接近强一致 | 中 | 高 | 写少读多 |
常见误区:
适用边界:
【结论】 缓存一致性本质是写库与写缓存的竞态,方案按一致性强度递进:TTL 兜底 → Cache Aside 删缓存 → 延迟双删 → binlog 订阅;写侧用"删缓存"比"更新缓存"更稳。
【三点】
第一,根因与兜底:写库与缓存更新非原子,先接受最终一致,TTL 保证最终收敛。
第二,删除策略:写库后删缓存(Cache Aside),下次读重建;高并发下用延迟双删(删 → 等写库+读回填窗口 → 再删)覆盖旧值回填。
第三,可靠一致:复杂场景订阅 binlog(Canal)监听变更触发删除,解耦可重试;要求强一致则读后回填 + 控制读写顺序。
【边界】 强一致缓存需串行化读写,代价高;TTL/删除只给最终一致;binlog 有解析延迟与运维成本,需权衡后选型;延迟双删的延迟窗口要覆盖"写库 + 读回填"耗时,估算偏小会导致旧值残留。
题目:如何保证本地缓存的一致性?
难度:medium
标签:cache/consistency, local-cache, general/knowledge, difficulty/medium
评分:⭐⭐⭐⭐☆(4/5)
缓存一致性基本都不会是强一致性的,核心是数据更新后缓存没有更新产生的不一致中间状态;
要解决这个问题,最简单的就是给缓存设置过期时间,过期时间到了有访问,自然会重新获取,这样中间会有不一致的过程,但是最终会一致的,主要用在可以接受不一致的场景;
另外就是当数据库更新后,删除缓存,等待下次调用将缓存设置上,这样如果有访问的很快就能设置上缓存;但是高并发下可能会出现,删除过程中新的访问写入了旧的数据导致缓存不一致,这块延伸的处理是延迟双删,启一个子任务过一会再删除缓存;
另外复杂度要求高的,可以通过订阅数据库binlog日志,检测数据库变动,触发式的进行缓存删除;
以及当数据库变更后,直接从主线程读取数据直接设置缓存,来保证强一致
评分:⭐⭐⭐⭐☆(4/5)
优点:结构化——先点明"基本非强一致、不一致中间态";TTL 兜底最终一致;Cache Aside 更新后删缓存;高并发竞态→延迟双删;复杂场景→订阅 binlog 触发删除;读后回填强一致。层次清晰。
不足:没区分 Cache Aside / Write Through / Write Back 三种模式;延迟双删的"第二次删除失败"重试未提;"先删缓存后更新库 vs 先更新库后删缓存"的取舍未展开。
补充:补①Cache Aside / Write Through / Write Back 区分;②延迟双删第二次删除失败的重试;③缓存击穿/穿透/雪崩(读侧)与一致性(写侧)的分层。
完整讲解见上方「完整讲解(权威版)」