
CDN 控制台里的命中率保持在高位,源站出口带宽却持续上涨,这两件事可以同时发生。按请求数计算的命中率无法直接说明省下了多少字节;边缘节点的未命中,也未必意味着请求已经抵达源站。
排查时需要把三个量放在同一个时间窗口:访客请求数、CDN 到源站的请求数,以及源站发出的字节数。再按域名、路径和状态码拆开看,通常就能判断增量来自大文件、动态接口、缓存更新,还是绕过 CDN 的访问。下面的方法适用于有 CDN 访问日志、源站日志或对象存储访问记录的站点,具体字段以服务商定义为准。
请求命中率高,为什么仍然可能回源很多
假设一个观察窗口内有 10 万次请求,其中 9.9 万次命中,每次只有 2 KB;剩下 1000 次未命中,每次都要从源站读取 20 MB。请求命中率达到 99%,源站仍需要传输约 20 GB 数据。这个例子只用于解释量级,未计协议开销、压缩、重试及缓存分层。
还有一种更直接的情况:请求总量翻倍,命中率保持不变,未命中请求的绝对数量也可能翻倍。只比较百分比,很容易漏掉这部分增长。
因此,优先确认控制台显示的是请求命中率、字节命中率,还是仅针对可缓存请求计算的命中率。动态接口可能不在某个图表的分母内。报表里的流量也可能指下行字节、计费流量或回源流量,它们不能混着使用。
先把源站出口和 CDN 回源统计对齐
从带宽上涨最明显的一个短时间窗口开始,核对以下条件:
| 需要对齐的项目 | 常见误差 |
|---|---|
| 时间与粒度 | 本地时区与 UTC 混用,分钟峰值与小时平均值比较 |
| 资源范围 | 单个 CDN 域名与整台源站、整个存储桶比较 |
| 数据方向 | 源站总出站包含备份、复制或其他业务 |
| 请求与字节 | 请求命中率被误当作字节节省率 |
| 采样与延迟 | 采样日志外推有误,报表尚未完成聚合 |
源站监控如果只提供网卡总出口,就无法直接归因给 CDN。先利用虚拟主机日志、负载均衡日志或对象存储访问记录缩小范围。访问凭证、签名参数和用户标识应脱敏,排查文件也应设置访问限制。
边缘 MISS 不一定打到了源站
多层缓存中,边缘节点未命中后,可能向上层缓存请求对象;上层已经持有对象时,源站并不需要重新发送完整内容。反过来,缓存层级或回源路径调整后,边缘命中率变化不明显,源站请求仍可能增加。
AWS 文档说明,CloudFront Origin Shield 在现有缓存层与源站之间增加一层缓存,并能合并针对同一对象的并发请求,以减少到达源站的请求。这是特定产品能力,是否启用、如何选择区域以及额外费用,都应以账户配置和当前文档为准。[1]
核对最近是否关闭过上层缓存、改过 Origin Shield、切换源站,或者让部分路径使用了另一套缓存行为。不要根据某一条响应里的 MISS 直接统计源站负载:缓存状态头的含义、覆盖层级及可见范围由平台决定。源站日志与 CDN 回源日志相互印证,证据更可靠。
找出增加的是哪些路径、状态码和字节
在异常窗口与一个可比窗口中,分别按路径或对象前缀统计请求数和实际发送字节。优先检查以下几类增量:
下载包、视频或备份文件:少量请求就可能贡献大量字节,需要同时看 200、206 与完整对象大小。
不缓存的接口:流量增长会直接传递给源站,不能用静态资源的高命中率替它解释。
条件请求:304 通常不带响应内容,但仍产生源站请求及处理开销;应区分请求增加与字节增加。
错误与重试:回源失败后可能发生重试,客户端也可能再次请求,不能把每一次源站请求都算成一个新访客。
刷新与发布:批量失效后,各缓存节点重新填充;对象更新频率高或热门内容同时过期,也可能形成回源峰值。
HTTP 缓存规范允许缓存通过验证请求判断已有响应是否仍可使用;no-cache 要求在复用前成功验证,不能简单理解成“完全不存储”。no-store 则约束存储行为。[2] 调整这些响应头之前,应确认它们在当前 CDN 缓存规则中的生效方式,不能靠延长所有页面的 TTL 来降低账单,登录态和私有内容尤其不能因此进入公共缓存。
用受控请求留下一组响应证据
下面的示例适合在已经获准访问的测试静态文件上执行。替换域名和路径后,只请求一个较小对象,避免对大文件反复完整下载。
curl -sS --max-time 15 \
-D cdn-headers.txt -o /dev/null \
-w 'code=%{http_code} downloaded=%{size_download} time=%{time_total}\n' \
'https://cdn.example.com/test/small-versioned-file.txt'记录执行时间、响应状态、Age、Cache-Control、ETag 以及平台提供的缓存状态和请求标识。Age 缺失不能单独证明未缓存,存在也不能替代完整链路判断。size_download 是这次客户端传输的响应内容字节数,不能直接当成源站回源字节数。
本例使用 GET;HEAD 在某些系统中的处理与缓存行为可能不同。不要为了制造 MISS 不断添加随机查询参数,它们是否进入缓存键取决于配置,还可能额外制造回源。请求侧 Cache-Control: no-cache 也不能作为所有 CDN 通用的强制穿透开关。
确认有没有绕过 CDN 的出口流量
如果源站记录的请求增长明显大于 CDN 侧观察到的回源增长,检查还有哪些入口在访问同一台服务器:旧域名、公开的存储桶地址、未代理的解析、监控、搜索抓取,以及直连源站的程序。
源站日志中的客户端地址可能已经被真实访客 IP 模块改写。此时,需要同时保留实际网络对端与可信代理解析后的访客地址,避免根据一个字段误判直连来源。X-Forwarded-For 可以被伪造,不能单独用作访问授权证据。
收紧源站访问前,清点健康检查、运维入口、证书验证和必要的第三方回调。按平台支持的机制使用源站鉴权、私网回源或维护 CDN 出口地址允许列表,并先在小范围验证。不能只凭“地址看起来不是 CDN”就批量封禁生产流量。
按证据修复,并保留回滚入口
如果增量集中在少量大文件,检查对象是否可以安全缓存、版本化 URL 是否稳定,以及 Range 请求的产品行为。分片或范围请求不保证源站只传输相同大小的数据,具体填充策略需要结合服务商文档和源站日志核对。
如果增量来自缓存填充,检查最近的失效任务、发布节奏和 TTL 分布。优先采用版本化资源与精确失效,避免全站刷新反复冲掉热点对象。对符合条件的公开资源,可在测试后考虑上层缓存或请求合并;这些功能的适用范围和费用并不相同。
如果增量来自动态接口或重试,处理接口负载、超时预算和重试策略。写请求还需要幂等保障,不能仅为降低回源而强行缓存。
每次只变更一个可识别的规则或路径组,保存原配置、变更时间与回退方式。验收同时观察源站请求数、源站发送字节、错误率和响应延迟,并覆盖一个与原异常可比的业务窗口。确认费用时还要回到服务商计费口径,日志中的正文大小未必包含全部计费开销。
最终应能说明:哪一组请求贡献了多少增量,这组请求是否经过 CDN、是否到达源站,以及修改后减少的是请求还是字节。这个判断比单独追求更高的命中率更有用。
参考资料
资料核验日期:2026 年 11 月 6 日。本文为排查方法与示例,未声称在读者的生产环境完成测试。