CDN 与 WAF 精讲教程 / 第04章 缓存策略
第04章 缓存策略
缓存是 CDN 的核心能力。本章全面讲解缓存规则设计、缓存键(Cache Key)构造、缓存失效机制、预热策略以及分层缓存架构。
4.1 缓存规则
4.1.1 缓存规则类型
CDN 通常支持多层级缓存规则匹配:
| 优先级 | 匹配维度 | 示例 |
|---|---|---|
| 1(最高) | 完整 URL 路径 | /api/user/profile |
| 2 | URL 路径前缀 | /static/ |
| 3 | 文件扩展名 | *.jpg, *.js |
| 4 | 请求头 | Cookie / Authorization |
| 5(最低) | 默认规则 | /* |
4.1.2 常见缓存规则配置
┌─────────────────────────────────────────────────────────────┐
│ 缓存规则矩阵 │
├──────────────┬────────┬─────────────┬───────────────────────┤
│ 资源类型 │ TTL │ 缓存级别 │ 更新方式 │
├──────────────┼────────┼─────────────┼───────────────────────┤
│ HTML 页面 │ 60-300s│ 边缘 + 中间层│ 文件名不变 │
│ CSS/JS │ 1 年 │ 全层级 │ 文件名带 hash │
│ 图片 │ 30 天 │ 全层级 │ 主动 Purge │
│ API (GET) │ 0-60s │ 仅边缘 │ 短 TTL + 主动失效 │
│ API (POST) │ 不缓存 │ — │ — │
│ 视频 (HLS) │ 1-7 天 │ 全层级 │ 片段级更新 │
│ 字体 │ 1 年 │ 全层级 │ 版本号变更 │
│ 文档 (PDF) │ 7 天 │ 全层级 │ URL 变更 / Purge │
└──────────────┴────────┴─────────────┴───────────────────────┘
4.1.3 条件缓存规则
# Nginx 缓存规则示例
location ~* \.(jpg|jpeg|png|gif|webp|avif|ico)$ {
expires 30d;
add_header Cache-Control "public, immutable";
add_header CDN-Cache-Control "max-age=2592000";
}
location ~* \.(css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location /api/ {
# 不缓存 API 请求
add_header Cache-Control "no-store";
add_header CDN-Cache-Control "no-store";
}
location / {
# 首页短缓存
expires 5m;
add_header Cache-Control "public, s-maxage=300, stale-while-revalidate=60";
}
4.2 缓存键(Cache Key)
4.2.1 什么是缓存键
Cache Key 是 CDN 用来标识和查找缓存对象的唯一标识符。两个请求如果 Cache Key 相同,则它们会共享同一份缓存。
4.2.2 默认缓存键
默认 Cache Key = Scheme + Host + Port + Path + Query String
示例:
https://example.com:443/style/main.css?v=2
├── scheme: https
├── host: example.com
├── port: 443
├── path: /style/main.css
└── query: ?v=2
完整键: "https:example.com:443:/style/main.css?v=2"
4.2.3 自定义缓存键策略
| 策略 | 适用场景 | 说明 |
|---|---|---|
| 忽略查询参数 | SPA 应用 | ?utm_source 等追踪参数不影响内容 |
| 忽略特定参数 | 电商 | 只保留影响内容的参数 |
| 包含设备类型 | 响应式网站 | PC / Mobile 不同内容 |
| 包含语言 | 多语言网站 | Accept-Language 影响内容 |
| 包含 Cookie | 个性化内容 | 需注意缓存碎片化 |
| 忽略端口 | 默认端口 | 80/443 不应产生不同缓存 |
4.2.4 缓存键设计陷阱
❌ 错误示例:完整查询参数作为缓存键
/product?id=123&ref=google
/product?id=123&ref=baidu
/product?id=123&ref=wechat
→ 同一商品页面产生 3 份缓存!(缓存碎片化)
✅ 正确示例:忽略无关参数
Cache Key = Path + "id" 参数
/product?id=123 → 只产生 1 份缓存
4.3 缓存失效(Cache Invalidation)
4.3.1 失效方式
| 方式 | 原理 | 适用场景 | 粒度 |
|---|---|---|---|
| TTL 过期 | 缓存超过 max-age 后自动失效 | 通用 | 被动 |
| 主动 Purge | 手动/API 触发清除缓存 | 内容更新 | URL / 标签 / 全局 |
| 版本化 URL | 文件名中嵌入 hash,新版本用新 URL | CSS/JS 部署 | 精确 |
| Purge-Soft | 标记为过期,下次请求异步回源 | 灰度发布 | URL |
4.3.2 主动 Purge API 示例
# Cloudflare Purge by URL
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" \
-H "Authorization: Bearer {api_token}" \
-H "Content-Type: application/json" \
--data '{"files":["https://example.com/style/main.css"]}'
# Cloudflare Purge by Tag (Cache-Tag)
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" \
-H "Authorization: Bearer {api_token}" \
-H "Content-Type: application/json" \
--data '{"tags":["product-123","category-books"]}'
# 阿里云 CDN 缓存刷新
aliyun cdn RefreshObjectCaches \
--ObjectPath "https://example.com/style/main.css" \
--ObjectType File
4.3.3 版本化 URL 策略
<!-- 文件名嵌入 hash:每次构建生成新文件名 -->
<link rel="stylesheet" href="/static/css/main.a1b2c3d4.css">
<script src="/static/js/app.e5f6g7h8.js"></script>
<!-- 优势:
1. 无需 Purge 旧缓存
2. 可设置 max-age=1 年(immutable)
3. 新版本自动使用新 URL → 新缓存
4. 回滚只需恢复旧 HTML 中的引用
-->
4.4 缓存预热(Cache Preheat)
4.4.1 预热场景
| 场景 | 时间 | 说明 |
|---|---|---|
| 大促活动 | 活动前 1-2 小时 | 提前缓存活动页面、商品图片 |
| 版本发布 | 发布时 | 新 CSS/JS 推送到边缘 |
| 热点内容 | 突发事件 | 新闻/短视频爆发前预热 |
| 新站上线 | 上线前 | 首次访问不至于全部 MISS |
4.4.2 预热流程
预热流程:
┌──────────────┐
│ 预热任务触发 │ 手动/API/定时
└──────┬───────┘
▼
┌──────────────┐
│ URL 列表 │ 需要预热的资源清单
└──────┬───────┘
▼
┌──────────────┐
│ 分批推送 │ 控制并发,避免打爆源站
│ 100 URL/批 │
└──────┬───────┘
▼
┌──────────────┐
│ 边缘节点回源 │ 模拟 Cache Miss → 回源获取
└──────┬───────┘
▼
┌──────────────┐
│ 缓存写入 │ 存入边缘缓存存储
└──────┬───────┘
▼
┌──────────────┐
│ 验证命中率 │ 抽样检查 HIT 状态
└──────────────┘
⚠️ 注意:预热应在流量低峰期进行,避免回源风暴。建议分批执行,每批间隔 1-2 分钟。
4.5 分层缓存(Tiered Caching)
4.5.1 分层缓存架构
┌──────────────────────────────────────────────────────────────────┐
│ 分层缓存架构 │
│ │
│ 用户请求 │
│ │ │
│ ▼ │
│ ┌────────────────────┐ │
│ │ 边缘缓存 (L1) │ 命中率: 60-85% │
│ │ 特点: 最近、最快 │ 存储: 热点数据 │
│ └────────┬───────────┘ │
│ │ MISS │
│ ▼ │
│ ┌────────────────────┐ │
│ │ 中间层缓存 (L2) │ 额外命中: 10-20% │
│ │ Shield 节点 │ 存储: 温数据 │
│ └────────┬───────────┘ │
│ │ MISS │
│ ▼ │
│ ┌────────────────────┐ │
│ │ 源站 (L3) │ 最终来源 │
│ │ 数据库 / Object │ │
│ └────────────────────┘ │
│ │
│ 总体命中率: 70-99%(取决于内容类型和访问模式) │
└──────────────────────────────────────────────────────────────────┘
4.5.2 Shield 回源盾
Shield(回源盾) 是分层缓存的关键组件。在众多边缘节点中,指定一个(或少数几个)节点作为统一回源入口:
| 特性 | 无 Shield | 有 Shield |
|---|---|---|
| 回源请求数 | N 个节点 × 各自回源 | 1 次统一回源 |
| 源站压力 | 高 | 极低 |
| 缓存命中率 | 各节点独立 | Shield 汇聚共享 |
| 跨区域延迟 | — | Shield 到源站优化路由 |
| 故障影响 | 仅影响单个 PoP | Shield 故障影响所有 |
4.5.3 缓存命中率优化
| 优化手段 | 说明 | 预期提升 |
|---|---|---|
| 扩大缓存范围 | 更多资源类型纳入缓存 | +5-15% |
| 延长 TTL | 从 1 小时提升到 1 天 | +10-20% |
| Vary 头精简 | 减少 Vary 维度 | +5-10% |
| 回源合并 | 防止并发回源重复 | +0%(减少源站压力) |
| 启用 Shield | 跨节点共享缓存 | +10-20% |
| 忽略无关参数 | 优化 Cache Key | +5-15% |
4.6 高级缓存模式
4.6.1 边缘侧包含(ESI)
ESI(Edge Side Includes) 允许在 CDN 边缘组装页面的不同部分:
<!-- 主页面缓存 5 分钟 -->
<html>
<body>
<!-- 头部:缓存 1 小时 -->
<esi:include src="/fragment/header" ttl="3600"/>
<!-- 内容:缓存 5 分钟 -->
<esi:include src="/fragment/content?id=123" ttl="300"/>
<!-- 推荐:缓存 30 秒(高频变化) -->
<esi:include src="/fragment/recommendations" ttl="30"/>
</body>
</html>
| 优点 | 缺点 |
|---|---|
| 页面各部分独立缓存,提高命中率 | 仅部分 CDN 厂商支持 |
| 减少回源传输量 | 增加边缘处理复杂度 |
| 个性化 + 缓存兼得 | 调试困难 |
4.6.2 负面缓存(Negative Caching)
# 对 404 响应短时间缓存,防止缓存穿透
location / {
proxy_cache_valid 200 301 302 10m;
proxy_cache_valid 404 1m; # 404 缓存 1 分钟
proxy_cache_valid any 5m;
}
| 场景 | 策略 | 原因 |
|---|---|---|
| 404 Not Found | 缓存 1-5 分钟 | 防止缓存穿透 |
| 5xx Error | 不缓存或极短缓存 | 允许快速恢复 |
| 302 Redirect | 缓存重定向 | 减少重复解析 |
4.7 注意事项
⚠️ 缓存一致性:CDN 缓存是最终一致性模型。主动 Purge 也需要一定时间传播到全球节点。
⚠️ 私有内容:包含
Authorization头的请求默认不缓存。如需缓存,务必确认无敏感信息泄露。⚠️ Set-Cookie 响应:带有
Set-Cookie的响应通常会被 CDN 跳过缓存。如果需要缓存,应在源站剥离 Cookie。⚠️ Vary: Cookie:此设置会导致每个不同的 Cookie 值生成一份缓存,极易导致缓存命中率崩塌。
4.8 扩展阅读
- RFC 9111 - HTTP Caching — HTTP 缓存权威规范
- Varnish Book - Cache Invalidation — Varnish 缓存失效策略
- Cloudflare Cache Rules — Cloudflare 缓存配置详解
- Akamai Caching Guide — Akamai 缓存最佳实践
本章小结
| 主题 | 核心要点 |
|---|---|
| 缓存规则 | 按 URL/路径/扩展名分层配置 TTL |
| 缓存键 | 合理设计避免缓存碎片化 |
| 缓存失效 | TTL + 主动 Purge + 版本化 URL |
| 预热 | 大促/发布前主动推送缓存 |
| 分层缓存 | L1(Edge) + L2(Shield) + L3(Origin) |
下一章:第05章 CDN 性能优化 →