CDN 缓存命中率优化技巧:提升 CDN 加速效果的实战策略
缓存命中率是 CDN 成本与体验的"双重仪表盘":命中率越高,回源请求越少,源站压力越小,用户拿到内容的延迟越低,账单上的回源流量费也越少。很多站长只盯着"有没有开 CDN",却从不看命中率,结果加速效果平平、费用却不低。这篇文章把能立刻上手的技巧按优先级过一遍。
一、先理解两个命中率
- 字节命中率 (Byte Hit Ratio):CDN 直接响应的流量占比,一般应 > 85%
- 请求命中率 (Request Hit Ratio):CDN 直接处理的请求占比,一般应 > 90%
两者不同:HTML 页面请求少但字节小,图片请求多、字节大。一个站如果字节命中率低,多半是动态内容或未缓存的接口在拖后腿。所以排查时两个指标要一起看:请求命中率低多半是动态接口,字节命中率低多半是图片或视频没缓存好。
常见内容的理想命中率
| 内容类型 | 理想命中率 | 说明 |
|---|---|---|
| 图片 | > 95% | 基本不变 |
| CSS/JS | > 95% | 版本更新时变化 |
| 字体文件 | > 99% | 几乎不变 |
| HTML 页面 | 50-80% | 取决于变化频率 |
| API 响应 | 0-50% | 取决于可缓存性 |
二、八个能落地的优化技巧
技巧 1:按资源类型设置 TTL
不要一刀切。图片给 30 天 + immutable,带版本号的 CSS/JS 给一年,HTML 只给 1 小时:
# 图片 - 长时间缓存
location ~* \.(jpg|jpeg|png|gif|ico|svg)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# CSS/JS - 带版本号
location ~* \.(css|js)$ {
expires 365d;
add_header Cache-Control "public, immutable";
}
# HTML - 短缓存
location ~* \.html$ {
expires 1h;
add_header Cache-Control "public, must-revalidate";
}
TTL 之外,s-maxage 和 stale-if-error 这类指令也可以组合使用:前者控制共享缓存(CDN)的时长,后者让源站挂了还能继续吐旧内容,容错性更好。
技巧 2:文件版本化,而不是查询参数
style.css?v=1 这种"查询参数版本号"在很多 CDN 眼里是不同 URL,等于每次发布都要回源;把哈希写进文件名才是标准做法,还能配合 immutable 缓存一年:
# ❌ 不推荐
style.css?v=1
# ✅ 推荐
style.a1b2c3d4.css
main.55e8c9f1.js
现代构建工具(Vite、Webpack、Next.js)默认就产出带哈希的文件名,直接在构建配置里打开就行。配合 Service Worker 或构建产物的 preload,版本化文件还能进一步做骨架缓存,但这属于锦上添花,先把哈希文件名做对。
技巧 3:去掉 URL 里的动态参数
带 Session ID、随机 token 的 URL 会制造海量"假唯一"的缓存条目,把命中率拉低。能用 ignore query string 的 CDN 功能就开,命中率往往立竿见影。但注意:如果参数真的影响响应内容(比如分页),别盲目忽略,先改成规范的分页路径再说。
技巧 4:清理响应里的 Cookie
Set-Cookie 会直接阻断 CDN 缓存。静态资源上把 Cookie 清掉,动态页再交给专门策略:
# 静态资源清除 Cookie
location ~* \.(jpg|css|js)$ {
add_header Cache-Control "public";
add_header Set-Cookie "";
}
技巧 5:预取热门内容
CDN 预取(Pre-fetch)在空闲时把热门 MISS 内容主动拉到边缘节点,下次用户访问直接命中:
CDN 预取策略:
1. 分析缓存 MISS 请求
2. 识别热门 MISS 内容
3. 主动拉取到边缘节点
4. 减少下次 MISS
技巧 6:分层缓存
边缘节点 TTL 短、更新快;中层节点 TTL 长、容量大。回源只发生在中层,源站压力直接降一个数量级:
用户 → 边缘节点 (100ms TTL) → 中层节点 (1h TTL) → 源站
技巧 7:缓存 POST 响应
对"同参数同结果"的查询类 POST,部分 CDN 支持按请求体缓存响应(需确认支持),能显著降回源:
Cache-Control: public, max-age=3600
CDN-Cache: POST requests with same body
技巧 8:用日志找问题资源
定期拉 HIT/MISS 分布,把 MISS 占比最高的资源按字节排序,优先处理"又大又 MISS"的图片和 JS。
两个进阶玩法值得单独说。一是 stale-while-revalidate:让 CDN 先返回旧缓存、后台悄悄刷新,用户永远等不到回源的那一下,适合新闻、榜单这类内容;二是 Vary 头:同一 URL 根据设备类型返回不同版本时,Vary: User-Agent 会拆出多份缓存,用错了反而拉低命中率,优先改用 URL 区分(如 m. 域名或路径前缀)。
参考:Cloudflare 缓存文档 https://developers.cloudflare.com/cache/;HTTP Cache-Control 规范 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
三、一个真实调优案例
某图片站启用 CDN 后命中率只有 68%。查日志发现两个问题:一半流量来自一张带随机时间戳参数的轮播图接口,另一半来自没开 immutable 的雪碧图。处理方式是:轮播图接口走 CDN 的忽略查询参数规则,构建脚本给静态资源文件名加哈希并开 immutable。一周后字节命中率升到 94%,源站带宽费降了 40%。
16IDC 建议
先跑一周基线,记录命中率和回源流量;然后按"TTL → 版本化 → 去动态参数 → Cookie"的顺序逐项优化,每改一项等两三天再看数据,避免一次改太多分不清谁起的作用。对加载速度敏感的场景,命中率从 70% 提到 95%,体感差距非常明显。另外建议把命中率和回源字节数挂进监控面板,跟源站 CPU/带宽联动看,回源突然上涨往往就是命中率波动的先兆。