一致性与缓存更新策略
缓存一致性讨论的是数据库和 Redis 之间的状态同步。绝大多数业务无法做到低成本强一致,因此要明确允许的不一致窗口,并用删除缓存、延迟双删、消息订阅、版本号等策略控制风险。
# 1. 学习定位
| 维度 | 内容 |
|---|---|
| 难度层级 | 架构核心 |
| 核心目标 | 先会用,再理解机制,最后能做工程取舍和故障分析 |
| 学习方法 | 带着业务场景看命令、SQL、数据结构、日志和运行时指标 |
# 2. 核心地图
一致性与缓存更新策略
├─ 先写库后删缓存
├─ 先删缓存后写库
├─ 延迟双删
├─ 订阅 binlog
├─ 版本号
├─ 逻辑过期
└─ 幂等更新
# 3. 小章节深度讲解
下面把核心地图中的每个点拆开讲。每个小节都同时面向开发和运维:开发侧关注怎么设计、怎么写代码、怎么避免错误;运维侧关注怎么监控、怎么定位、怎么恢复。
# 3.1. 先写库后删缓存
# 是什么
先写库后删缓存 属于缓存稳定性问题。缓存不是简单加速层,它决定数据库回源压力、数据新鲜度、热点保护和故障降级。
# 开发人员怎么用
开发人员要为不同数据定义 TTL、随机抖动、空值缓存、热点重建和一致性策略。写库删缓存、延迟双删、binlog 订阅都要配合失败补偿。
# 运维人员怎么看
运维人员要监控命中率、过期速率、淘汰数量、热点 key、大 key、回源量和数据库压力。Redis 故障时要看数据库是否被缓存失效放大。
# 常见风险
常见风险是大量 key 同时过期或热点 key 硬过期,瞬间把所有请求打回数据库。缓存系统必须有保护数据库的设计。
# 3.2. 先删缓存后写库
# 是什么
先删缓存后写库 属于缓存稳定性问题。缓存不是简单加速层,它决定数据库回源压力、数据新鲜度、热点保护和故障降级。
# 开发人员怎么用
开发人员要为不同数据定义 TTL、随机抖动、空值缓存、热点重建和一致性策略。写库删缓存、延迟双删、binlog 订阅都要配合失败补偿。
# 运维人员怎么看
运维人员要监控命中率、过期速率、淘汰数量、热点 key、大 key、回源量和数据库压力。Redis 故障时要看数据库是否被缓存失效放大。
# 常见风险
常见风险是大量 key 同时过期或热点 key 硬过期,瞬间把所有请求打回数据库。缓存系统必须有保护数据库的设计。
# 3.3. 延迟双删
# 是什么
延迟双删 属于 Redis 高可用和运行时协调。它影响故障检测速度、切换正确性、复制延迟和客户端重连表现。
# 开发人员怎么用
开发人员要处理短暂不可用、读旧数据、连接重建和请求重试。客户端必须支持 Sentinel 或 Cluster 的发现协议。
# 运维人员怎么看
运维人员要设置合理 quorum、超时、复制 backlog 和告警阈值,并演练主库故障、网络分区和客户端重连。
# 常见风险
常见风险是 Sentinel 判断切换成功,但客户端仍缓存旧地址;或者后台任务、复制和持久化延迟叠加,导致业务侧误判 Redis 已不可用。
# 3.4. 订阅 binlog
# 是什么
订阅 binlog 属于 Redis 具体数据结构能力或缓存策略。它的价值取决于访问模式、数据规模、误差边界和失败补偿。
# 开发人员怎么用
开发人员要明确它服务的是计数、范围查询、近似统计、缓存回源、降级还是一致性控制,并写清楚异常和重复执行时的语义。
# 运维人员怎么看
运维人员要观察命令复杂度、返回大小、内存增长、命中率、回源量和慢命令。近似结构还要关注误差是否被业务接受。
# 常见风险
常见风险是把策略名当答案。比如 Cache Aside 仍要处理删缓存失败,近似统计不能用于财务精确结果,复杂搜索不能和核心缓存混用。
# 3.5. 版本号
# 是什么
版本号 属于 Redis 具体数据结构能力或缓存策略。它的价值取决于访问模式、数据规模、误差边界和失败补偿。
# 开发人员怎么用
开发人员要明确它服务的是计数、范围查询、近似统计、缓存回源、降级还是一致性控制,并写清楚异常和重复执行时的语义。
# 运维人员怎么看
运维人员要观察命令复杂度、返回大小、内存增长、命中率、回源量和慢命令。近似结构还要关注误差是否被业务接受。
# 常见风险
常见风险是把策略名当答案。比如 Cache Aside 仍要处理删缓存失败,近似统计不能用于财务精确结果,复杂搜索不能和核心缓存混用。
# 3.6. 逻辑过期
# 是什么
逻辑过期 属于缓存稳定性问题。缓存不是简单加速层,它决定数据库回源压力、数据新鲜度、热点保护和故障降级。
# 开发人员怎么用
开发人员要为不同数据定义 TTL、随机抖动、空值缓存、热点重建和一致性策略。写库删缓存、延迟双删、binlog 订阅都要配合失败补偿。
# 运维人员怎么看
运维人员要监控命中率、过期速率、淘汰数量、热点 key、大 key、回源量和数据库压力。Redis 故障时要看数据库是否被缓存失效放大。
# 常见风险
常见风险是大量 key 同时过期或热点 key 硬过期,瞬间把所有请求打回数据库。缓存系统必须有保护数据库的设计。
# 3.7. 幂等更新
# 是什么
幂等更新 属于 Redis 具体数据结构能力或缓存策略。它的价值取决于访问模式、数据规模、误差边界和失败补偿。
# 开发人员怎么用
开发人员要明确它服务的是计数、范围查询、近似统计、缓存回源、降级还是一致性控制,并写清楚异常和重复执行时的语义。
# 运维人员怎么看
运维人员要观察命令复杂度、返回大小、内存增长、命中率、回源量和慢命令。近似结构还要关注误差是否被业务接受。
# 常见风险
常见风险是把策略名当答案。比如 Cache Aside 仍要处理删缓存失败,近似统计不能用于财务精确结果,复杂搜索不能和核心缓存混用。
# 3.8. 本篇学习实验
建议准备一个独立 Redis 实例,构造小 key、大 key、热点 key、过期 key 和慢命令,观察 INFO、SLOWLOG、LATENCY、内存变化和客户端超时。每个实验都要记录命令复杂度和返回数据量。
开发侧实验重点是理解数据结构和命令边界,运维侧实验重点是理解延迟、内存和复制如何变化。真正掌握本篇内容,应该能从延迟尖刺反推大 key、慢命令、持久化或网络问题。
# 4. 核心机制
- Cache Aside 中常见策略是先更新数据库,再删除缓存,让下次读取回源重建。
- 直接更新缓存容易出现并发覆盖,尤其是旧请求后写入旧值。
- 延迟双删试图覆盖并发读写窗口,但延迟时间难以精确。
- 订阅 binlog 删除或更新缓存可以降低业务侵入,但链路更长,需要处理延迟和失败。
# 5. 工程实践
- 默认优先删除缓存,而不是更新缓存。
- 缓存值中加入版本号或更新时间,避免旧值覆盖新值。
- 关键数据读写后需要读己之写时,直接读数据库或使用短期本地上下文。
- 缓存更新链路要有失败重试、死信和补偿扫描。
# 6. 常见坑
- 写库成功但删缓存失败,旧缓存长期存在。
- 并发读重建旧值覆盖新值。
- 消息订阅延迟导致缓存长时间不一致。
- 把缓存一致性当强一致事务处理,方案复杂且脆弱。
# 7. 专家视角
- 缓存一致性是概率和窗口控制,不是魔法。
- 专家会按业务场景分层:价格、库存、配置、用户资料、排行榜的一致性要求不同。
- 一致性方案必须有补偿任务,否则任何一次失败都会留下脏缓存。
# 8. Tips 快问快答
Q:为什么常说更新数据库后删除缓存?
A:删除比更新更不容易写入旧值,下次读取可以用数据库真相源重建。
Q:延迟双删一定可靠吗?
A:不一定。它降低概率,但延迟时间和并发时序很难完全覆盖。
Q:缓存能做到强一致吗?
A:可以设计接近强一致的方案,但成本高,通常要看业务是否真的需要。
# 9. 阶段小结
一致性与缓存更新策略 的学习重点不是记住零散概念,而是把它放回真实系统:数据如何进入、如何存储、如何被查询、如何在并发下保持正确、如何在故障后恢复。掌握这些连接关系,才能从“会用”走向“能设计、能优化、能排障”。