9.4 预热、刷新与失效
一句话
预热是 “提前把新内容放上去”,刷新是 “让旧内容立刻作废”,失效(TTL)是 “让内容自己过期”;三者的顺序错了,发布就会变成一次回源风暴——这正是 “发完版源站就挂” 的标准剧本。
四个动作,四条语义
| 动作 | 做什么 | 生效速度 | 成本 | 什么时候用 |
|---|---|---|---|---|
| 预热 | 把指定 URL 主动拉到边缘 | 分钟级 | 占用回源带宽(等于提前 MISS) | 大促、发布前、热点内容 |
| 刷新(purge) | 让指定 URL 的缓存立即失效 | 秒–分钟级 | 刷新后首批请求会回源 | 线上内容必须立刻更正 |
| 失效(TTL) | 到期自然失效 | 由 TTL 决定 | 无 | 常规更新 |
| 版本化 | 换 URL(文件名带 hash) | 立即 | 需要构建支持 | 推荐的常规发布方式 |
🔑 版本化 > 刷新:把
app.js改成app.9f2c.js,新 URL 天然未命中、旧 URL 继续可服务。刷新是 “应急手段”,不是发布流程。
刷新:三种粒度,各有配额
| 粒度 | 例子 | 限制 | 适用 |
|---|---|---|---|
| URL 刷新 | /static/app.js | 单次有条数上限,高频调用被限速 | 精确修正 |
| 目录刷新 | /static/2026/ | 目录越大耗时越久 | 整批替换 |
| 正则/标签刷新 | ^/static/.*\.js$ | 部分厂商不支持,或风险高 | 兜底(慎用) |
三条纪律:
- 刷新有配额与频率限制(通常按天计),不是 “想刷就刷”。
- 刷新 ≠ 预取:刷新后第一个请求仍要回源,可能命中 “源站正在发布” 的窗口。
- 刷新传播需要时间(多级缓存 + 多节点),跨区域常见 1–5 分钟,别用 “刷新完立刻验证一次” 下结论。
预热:把 MISS 提前,但要算成本
| 项 | 说明 |
|---|---|
| 对象数 | 一次预热几千个对象就够;全站预热既慢又贵 |
| 并发 | 预热并发过高会打满源站,等于把发布流量提前 |
| 成本 | 预热产生的回源流量按正常回源计费 |
| 顺序 | 先预热新版本,再切流量/刷新,否则预热的是旧内容 |
正确的发布顺序:
- 构建产出带 hash 的新文件(版本化);
- 预热新文件到边缘(此时旧版本仍在服务);
- 切换引用(HTML/配置指向新文件);
- 旧文件保留一个 TTL 周期后自然淘汰,不刷新;
- 只有 “同 URL 必须改内容” 时才用刷新,并立即观察回源率。
软刷新:用 “旧内容 + 后台更新” 换可用性
| 指令 | 行为 | 适用 |
|---|---|---|
stale-while-revalidate=60 | 过期后先返回旧副本,后台异步刷新 | 首页、列表页 |
stale-if-error=300 | 回源失败时返回旧副本 | 源站抖动、发布期 |
must-revalidate | 过期后必须回源成功才能返回 | 价格、库存等强一致内容 |
代价是 “短时间的不一致”,收益是 “源站抖动时页面仍能打开”。对强一致内容(价格、库存、余额),应关闭软刷新并在应用层做版本校验。
反模式
| 反模式 | 后果 |
|---|---|
| 发布后全站刷新 | 全量 MISS → 回源风暴 → 源站被打挂 |
| 用刷新代替版本化 | 每次发布都依赖 “刷新生效”,故障面被放大 |
| 先切流量再预热 | 预热的是旧内容,新版本仍全量回源 |
| 预热整个 Bucket | 预热耗时超过发布窗口,且大部分对象无人访问 |
| 刷新后立刻验证一次就收工 | 边缘传播未完成,误判 “刷新失败” 又刷一次 |
给价格接口配 stale-if-error | 用户看到过期价格,引发资损或投诉 |
三条铁律
🔑 常规发布用版本化(换 URL),刷新只做应急。
🔑 先预热、再切流;顺序反了,预热等于没做。
🔑 刷新与预热都是 “回源流量的提前支付”,要按源站容量规划。
自检
Q1 为什么说 “发布后全站刷新” 是危险操作?
▸ 答案:因为刷新会让所有 URL 同时失效,紧接着的流量全部变成回源(且可能没有请求合并),源站在几秒内承受全站流量——这正是 “发布把源站打挂” 的典型路径。正确做法是版本化发布:新 URL 未命中是渐进的,旧 URL 继续服务,回源压力被摊开。
Q2 预热和刷新能互相替代吗?
▸ 答案:不能,方向相反。预热是 “往边缘放内容”(增加命中),刷新是 “把边缘内容作废”(强制回源)。发布新版本时应该 “预热新 URL + 不动旧 URL”;只有 “同一 URL 内容必须改” 时才刷新,且刷新后要立刻补预热,否则第一波用户仍要等回源。
Q3 刷新请求返回成功,但用户仍看到旧内容,为什么?
▸ 答案:三种可能:① 传播未完成(多级缓存 + 多节点,跨区 1–5 分钟);② 浏览器/客户端本地缓存(Cache-Control: max-age 很长,刷新 CDN 不影响浏览器);③ 刷新的是 A 域名/路径,用户访问的是 B(CDN 按域名与路径隔离)。诊断时先分清 “边缘是否已更新”,再看客户端缓存。
Q4 什么时候必须用 must-revalidate,不能用软刷新?
▸ 答案:当 “过期内容会造成错误决策或资损” 时:价格、库存、余额、优惠券状态。这类内容宁可返回错误(让前端提示重试),也不能返回过期值。反过来,首页推荐、文章列表、静态资源适合软刷新——短暂陈旧不影响正确性。
Q5 大促前应该怎么准备 CDN 缓存?
▸ 答案:分三步:① 容量:按预估峰值算回源带宽上限,确认源站与回源链路扛得住(见 9.2 回源策略与回源率);② 内容:把可枚举的热点对象(商品图、活动页、静态包)预热,键与 TTL 提前冻结;③ 降级:配好 stale-if-error 与降级页,并演练一次 “源站不可用”——大促当天不该第一次验证这些开关。
跨篇相关:命中率与回源的原理见 9.1 边缘缓存原理;回源限速与合并见 9.2 回源策略与回源率;键设计决定刷新粒度见 9.3 缓存键设计;CDN 的整体组成见 9.0 CDN 全景:它到底是什么;发布策略与灰度见 55.1 发布策略 (滚动 / 蓝绿 / 金丝雀);制品的版本化命名见 54.1 不可变制品。