Skip to content

05 · Redis 与缓存模式:Cache-Aside / Read-Through ​

Redis 不只是"快一点的 Map"。本篇讲清缓存放在数据访问链路的哪里、四种读写模式怎么选、以及最常见的"缓存与数据库不一致"怎么发生、怎么兜底。

速览卡 ​

项内容
一句话定位缓存的落地模式与一致性,从"会用 Redis 命令"到"会设计缓存链路"
核心内容Cache-Aside / Read-Through / Write-Through / Write-Behind、过期策略、一致性兜底
读完能回答为什么读走缓存、写要删缓存?先删缓存还是先写库?
相关板块DB06 缓存三大问题 | DB02 索引 | C13 缓存与 Redis

常用命令与结构(String/Hash/List/Set/ZSet、过期策略)见 C13;本篇讲读写模式与一致性。


一、缓存放在哪:数据访问链路的两种形态 ​

text
形态 A:应用自己管缓存(Cache-Aside 最常见)
  App → Redis → 未命中 → MySQL → 写回 Redis

形态 B:框架帮你管缓存(Read-Through)
  App → 缓存中间件 → 未命中 → 自动回源 DB → 自动回填
模式谁负责回填适用
Cache-Aside应用默认选择,控制力强
Read-Through缓存层/框架希望调用方无感知时

二、Cache-Aside:标准四步 ​

python
# 读
def get_user(user_id):
    user = redis.get(f"user:{user_id}")
    if user:
        return user
    user = db.query(User).get(user_id)      # 回源
    if user:
        redis.set(f"user:{user_id}", user, ex=3600)  # 回填
    return user

# 写
def update_user(user_id, data):
    db.query(User).filter(User.id == user_id).update(data)  # 1. 先写库
    redis.delete(f"user:{user_id}")                          # 2. 再删缓存

为什么写要"删缓存"而不是"更新缓存":更新需要算最终值、还要防并发写覆盖;删掉让下次读重建,简单且不容易错。


三、先删缓存还是先写库:一个经典顺序问题 ​

顺序风险结论
先写库后删缓存删缓存失败 → 旧数据多活一会更常用,配合延迟双删/对账
先删缓存后写库写库前有读回填旧值 → 旧数据停留更久更糟

兜底组合(延迟双删):

text
1. 先删缓存
2. 写库
3. 短延迟(几百 ms)后再删一次缓存

目的:覆盖"删完缓存 → 并发读回填旧值 → 写库完成"的窗口。 双删不是银弹,极端一致要上版本号/订阅 binlog 对账(见 C13)。


四、三种更新型缓存模式:何时才值得 ​

模式机制适用代价
Write-Through写库时同步写缓存读远多于写、要缓存总是新每次写多一次缓存写
Write-Behind先写缓存,后台批量落库极高写、能容忍短暂丢失丢失风险、复杂度
Cache-Aside(删)写库、删缓存默认有回源尖峰(见 DB06)

判断框架:绝大多数系统 Cache-Aside 就够。Write-Behind 带来的丢失风险通常不值得,除非写量已经大到必须批处理。


五、过期策略与键设计 ​

项建议
TTL必须设置,否则数据永久是旧的、内存也失控
键命名业务:实体:主键(user:123),可加版本前缀做发布兜底
不设 TTL 的高频热键用"逻辑过期"(值里带过期时间)配合主动刷新
大 key别把整个列表塞一个 key,考虑分片或只缓存摘要

TTL 语义:缓存不是"永远对",它是有界的"最近一致"。能接受多久的旧数据,就设多短的 TTL。


六、自检清单 ​

  • [ ] 默认用 Cache-Aside,知道读写各四步
  • [ ] 写操作用"删缓存"而不是"更新缓存"
  • [ ] 知道先删后写与先写后删的窗口差异,会用延迟双删兜底
  • [ ] 所有缓存都设 TTL
  • [ ] 键命名规范、避免大 key
  • [ ] 知道 Read-Through / Write-Through / Write-Behind 何时才值得

七、常见误区 ​

误区事实
"更新缓存比删缓存好"更新要算最终值且防并发覆盖,删更简单
"先删缓存就安全"先删后写反而更容易留下旧值
"缓存不用设 TTL"不设 TTL 会导致永久旧数据与内存失控
"Redis 能当唯一数据源"Redis 是易失的,业务数据要落库
"缓存一致性能做到绝对"网络/并发下只能做到"尽快一致",要对账兜底
"写多也走缓存"写多场景缓存的收益有限,代价不小

八、动手练习 ​

练习 A:设计用户资料缓存 ​

读多写少、允许 1 分钟旧数据。设计:键、TTL、读流程、写流程。写出关键代码。

练习 B:复现并发不一致 ​

两个线程同时对同一用户执行"更新用户"和"读取用户",模拟先删缓存后写库的窗口,观察旧值回填。再改成延迟双删重试。

练习 C:判断模式 ​

三个场景(商品详情、实时库存、埋点日志),分别选缓存模式并说明理由。


相关文档 ​

本区 ​

其他域 ​