为什么你的命中率上不去
很多站点接入 CDN 后发现命中率只有 50%~60%,加速效果远不如预期。命中率低意味着大量请求仍在回源——用户没享受到边缘的速度,源站也没减轻压力。绝大多数低命中率问题都能归结为三类原因:缓存键碎片化、响应头不配合、TTL 策略保守。
问题一:缓存键碎片化
CDN 默认用完整 URL(含查询参数)作为缓存键。下面这三个请求会被当作三个不同的对象分别缓存:
/logo.png?v=1 · /logo.png?from=weibo · /logo.png?t=1690001234
- 统计参数(utm_source、from 等):在 CDN 配置中忽略这些参数,同一资源合并为一个缓存对象;
- 时间戳防缓存参数:前端代码里的
?t=Date.now()是命中率杀手,应当移除,版本更新用固定的版本号参数; - 参数顺序:
?a=1&b=2与?b=2&a=1默认是两个键,开启参数排序归一化可以合并。
问题二:响应头不配合
源站的响应头会直接影响边缘节点的缓存行为,重点检查三个:
| 响应头 | 常见问题 | 建议 |
|---|---|---|
Cache-Control | 后端框架默认输出 no-cache / private | 静态资源改为 public, max-age=2592000 |
Set-Cookie | 静态资源响应带 Cookie,多数 CDN 会拒绝缓存 | 静态资源域名或路径不下发 Cookie |
Vary | Vary: User-Agent 会把缓存按 UA 拆成无数份 | 仅保留 Vary: Accept-Encoding |
如果不方便改源站,也可以直接在 CDN 控制台用缓存规则覆盖源站响应头:按路径或后缀强制设置缓存时间,优先级高于源站配置。
问题三:TTL 策略太保守
推荐一套分层 TTL 基线:
- 带哈希指纹的构建产物(app.3f2a1c.js):30 天甚至更长,内容变了文件名就变,不存在过期问题;
- 图片 / 字体 / 视频:7~30 天;
- HTML 页面:30~300 秒短缓存——看似很短,高并发下已能挡住 95% 以上的回源;
- API 接口:默认不缓存;对实时性要求不高的只读接口(如配置、榜单)可给 5~60 秒微缓存。
验证优化效果
- 在控制台「统计分析」查看命中率曲线,优化前后对比;
- 用浏览器开发者工具检查响应头中的缓存状态标识(HIT / MISS);
- 关注源站带宽变化——命中率从 60% 提到 95%,意味着回源流量降为原来的 1/8。
一个可复制的经验:先处理带参 URL 与 Set-Cookie(通常一次性解决 20~30 个百分点),再逐步拉长 TTL,最后用微缓存覆盖 HTML 与只读接口。
如果你还没接入 CDN,可以从《QEdgeCDN 接入教程》开始;想理解缓存的底层机制,请看《CDN 缓存如何提升网站访问性能》。