返回博客列表

CDN缓存命中怎么看?HIT、MISS和Age怎么理解

CdnChart 技术团队发布于 2026-09-1415 分钟阅读
CDN缓存命中怎么看?HIT、MISS和Age怎么理解

CDN已经接入,静态文件也能正常访问,但打开响应头一看:

CF-Cache-Status: MISS
Age: 0

刷新一次,又变成:

CF-Cache-Status: HIT
Age: 18

很多人看到这里会开始犯嘀咕:第一次 MISS 是不是说明CDN没有生效?Age: 18 是缓存还剩18秒,还是这个文件已经存在18秒?如果一直没有 Age,是不是所有请求都在回源?

其实,判断CDN缓存不能只截取一个字段,也不能只请求一次。你需要把缓存状态、Age、缓存控制头、请求URL和检测节点放在一起看。

先给出最短的答案:

字段或状态

通常表示什么

不能直接得出什么结论

HIT

当前缓存层找到了可复用的响应,并直接提供给本次请求

不代表所有地区、所有URL都命中

MISS

当前缓存层没有找到可直接使用的对象,需要向上游取内容

不一定表示每一层都没有缓存,也不等于CDN没生效

Age: 18

响应自源站生成或最近一次成功验证后,估算已经过去18秒

不是响应耗时,也不一定是剩余TTL

下面把这三个概念拆开讲清楚。

先确认:你看到的是哪家CDN的缓存头

HIT 和 MISS 是常见叫法,但CDN缓存状态并没有一个所有厂商完全一致的响应头名称。

你可能看到:

CF-Cache-Status: HIT

也可能看到:

X-Cache: Hit from cloudfront

还可能是某家厂商自己的 X-Cache-Status、X-CDN-Cache,或者只在控制台和访问日志里提供结果。相同单词在不同厂商、多层缓存和反向代理中的具体含义,也可能略有差异。

所以第一步不是死记字段,而是先确定:

  1. 当前域名使用了哪家CDN;

  2. 哪个响应头是这家CDN提供的;

  3. 网站前面是否还有另一层CDN、负载均衡或反向代理。

如果厂商不确定,可以先用 CdnChart CDN检测 查看CNAME、响应IP、ASN和HTTP响应头等线索,再对照厂商官方文档解释缓存状态。关于识别逻辑,也可以阅读如何判断网站使用了哪家CDN。

HIT是什么意思?

HIT 的核心含义是:当前负责响应的缓存层里,已经有一个满足本次请求条件、仍然可以使用的缓存对象。

请求过程大致是:

用户请求 → CDN节点查找缓存 → 找到可用对象 → 直接返回

与回源获取完整文件相比,缓存命中通常可以减少源站请求和跨区域传输。

不过,看到一次 HIT,只能证明这一次请求、这个URL、这个节点的缓存命中了。

它不能证明:

  • 其他城市或运营商的节点也已经缓存;

  • 首页引用的所有图片、脚本和接口都命中;

  • 不同查询参数、Cookie或请求头使用同一份缓存;

  • 整个网站的缓存命中率很高;

  • 当前配置一定安全、合理。

例如下面两个URL,在很多配置中属于两个不同的缓存键:

https://example.com/app.js?v=100
https://example.com/app.js?v=101

即使第一个URL已经 HIT,第二个URL第一次访问仍可能 MISS。如果系统给每次请求都追加随机参数,那么缓存就很难被复用。

MISS是什么意思?是不是一定回源了?

MISS 通常表示:当前缓存层没有找到可以直接用于本次请求的对象。

最常见的过程是:

用户请求 → 边缘节点未命中 → 从源站获取 → 返回并按规则缓存

所以,新文件第一次被某个节点访问时出现 MISS 很正常。只要响应允许缓存,第二次请求同一个URL,就可能变成 HIT。

但在现代CDN架构里,不能把所有 MISS 都简单翻译成“这次请求一定直接打到源站”。

原因是CDN可能存在两级甚至多级缓存:

用户 → 边缘节点 → 上层缓存 / Origin Shield → 源站

边缘节点本地没有对象,可以记一次本地 MISS;但上层缓存可能已经有内容,于是请求由上层缓存满足,源站并没有再次传输完整文件。

不同厂商暴露的是本地层、最终层还是汇总状态,要以其文档和日志为准。

此外,当多个用户几乎同时请求一个尚未缓存的大文件时,一些CDN会合并这些回源请求:第一个请求负责填充缓存,其余请求等待并复用结果。AWS在CloudFront自定义源站请求行为中将这种机制称为request collapsing,可以避免每个并发请求都单独访问源站。

因此,判断请求是否真正到达源站,最可靠的证据通常来自:

  • CDN控制台的回源请求数和回源流量;

  • CDN访问日志中的详细缓存状态;

  • 源站访问日志;

  • Origin Shield或上层缓存指标。

单个客户端看到的一个 MISS,只是线索,不是整个缓存链路的完整账单。

Age是什么意思?

Age 是标准HTTP响应头,单位是秒。

根据 RFC 9111 HTTP Caching,它表示缓存对“自响应由源站生成或最近一次成功验证以来已经过去多少秒”的估算。这个数值还会计入响应在缓存链路中的停留时间和传输时间。

例如:

Cache-Control: public, max-age=3600
Age: 600

可以粗略理解为:这份响应自生成或验证后已经过去约600秒。

如果没有其他缓存策略覆盖,并且 max-age=3600 确实是共享缓存采用的TTL,那么理论上还剩约3000秒的新鲜时间:

3600 - 600 = 3000秒

但这只能作为近似判断。

CDN可能配置了独立的边缘TTL,可能优先读取 s-maxage 或 CDN-Cache-Control,也可能存在分层缓存、重新验证和厂商自定义规则。所以,不能只凭 Age 反推最终过期时间。

Age不是什么

Age 很容易被误读。它不是:

  • 本次请求花费的时间;

  • 文件从创建至今的年龄;

  • DNS缓存的TTL;

  • 缓存还剩多少秒;

  • CDN节点运行了多久;

  • 静态资源的版本号。

Age: 120 不代表页面加载用了120秒,也不代表缓存只剩120秒。

Age为什么会越来越大?

在同一个缓存节点连续访问同一个URL时,如果每次都复用同一个缓存对象,Age 往往会随时间增大:

# 第一次
CF-Cache-Status: HIT
Age: 21

# 几秒后
CF-Cache-Status: HIT
Age: 27

这是比较典型的正常命中表现。

Age为什么会突然变小或归零?

常见原因有:

  • 请求被调度到另一个边缘节点;

  • 缓存被主动清除;

  • 对象过期后重新从源站获取;

  • 缓存对象被淘汰,再次填充;

  • CDN向源站重新验证后重置了年龄;

  • 多层缓存返回了不同层的年龄信息。

Cloudflare在缓存响应状态说明中指出,其 Age 会在重新验证、清除或驱逐后重置;使用分层缓存时,还可能继承上层缓存的 Age。

没有Age是不是就没有命中?

不是。

RFC 9111同时提醒:没有 Age,不能据此断定请求一定联系了源站。某些缓存或代理可能不公开该字段,某些响应状态也可能不带它。

反过来,有 Age 也不该脱离其他字段单独判断。有的上游代理或源站会传来自己的 Age,CDN也可能把它继续传递。

最好同时查看缓存状态、Via、厂商特征头和缓存控制策略。

除了HIT和MISS,还会看到哪些状态?

不同厂商的名称并不完全相同。下面是常见语义和典型示例,解释具体网站时,应以对应厂商的官方定义为准。

状态

常见含义

排查重点

HIT

找到可用缓存并返回

再看Age是否合理、不同地区是否一致

MISS

当前缓存层没有可直接使用的对象

首次访问、缓存键、TTL、是否成功写入缓存

BYPASS

对象原本可能进入缓存流程,但因响应头或规则绕过缓存

private、no-store、Set-Cookie、授权请求

DYNAMIC

请求在查缓存前就被判定为不适合缓存

URL规则、文件类型、缓存模式、动态页面

EXPIRED

已有对象过期,需要从上游取得新响应

TTL是否过短、源站是否正常

REVALIDATED/RefreshHit

上游确认内容未变化后继续使用缓存

ETag、Last-Modified、条件请求

STALE

缓存已过期,但在特定条件下仍返回旧副本

源站故障、stale策略、一致性要求

UPDATING

先返回旧缓存,同时在后台更新

是否开启后台刷新

NONE/UNKNOWN

响应在常规缓存流程之前产生,或未得到可识别状态

WAF、边缘函数、重定向和错误页

这里有两个容易混淆的点。

第一,BYPASS 和 DYNAMIC 都可能表现为请求去了上游,但原因不同:前者通常是响应头或规则让对象不被缓存,后者可能在请求阶段就被认定为动态内容。

第二,REVALIDATED 不等于重新下载整个文件。

CDN可以通过 If-None-Match 或 If-Modified-Since 向源站确认内容是否变化。如果源站返回 304 Not Modified,缓存便可以继续使用原对象。

CloudFront的日志中也使用 RefreshHit 表示对象过期后向源站确认,并继续使用缓存对象,具体定义可查阅AWS CloudFront标准日志字段。

怎样实际检查CDN缓存是否命中?

最实用的方法不是在浏览器里反复按刷新,而是固定条件,连续请求同一个公开静态资源。

第一步:选择适合测试的URL

优先选择:

  • 公共CSS或JavaScript文件;

  • 网站Logo、图片或字体;

  • 明确允许CDN缓存的下载文件;

  • 不需要登录、Cookie或授权头的资源。

不要一开始就拿首页、登录页、购物车或API接口测试。它们可能本来就不应该被共享缓存。

为了追求 HIT 而缓存私人页面,反而可能造成用户数据泄露。

第二步:查看完整响应头

把示例URL替换成你的真实静态资源:

curl -sS -D - -o /dev/null https://www.example.com/assets/app.css

参数含义:

  • -D -:把响应头输出到终端;

  • -o /dev/null:不保存响应正文;

  • -sS:减少进度信息,但保留错误提示。

有人习惯使用 curl -I 发送HEAD请求。它适合快速查看响应头,但有些CDN、源站或缓存规则对HEAD和GET的处理不同。

排查真实浏览器访问时,用GET请求并丢弃正文通常更接近实际情况。

重点观察这些字段:

Cache-Control: public, max-age=3600
CDN-Cache-Control: max-age=86400
CF-Cache-Status: HIT
X-Cache: Hit from cloudfront
Age: 245
ETag: "abc123"
Last-Modified: Thu, 10 Sep 2026 08:00:00 GMT
Via: ...

第三步:连续请求同一个URL

for i in 1 2 3; do
  printf 'Request %s\n' "$i"
  curl -sS -D - -o /dev/null https://www.example.com/assets/app.css \
    | grep -Ei '^(cache-control|cdn-cache-control|age|via|x-cache|cf-cache-status|etag|last-modified):'
  sleep 2
done

测试时要保持这些条件一致:

  • 完整URL相同,包括大小写和查询参数;

  • 不要每次附加随机时间戳;

  • 请求方法相同;

  • 不要一会儿带Cookie,一会儿不带;

  • 不要主动发送 Cache-Control: no-cache,除非正在测试重新验证;

  • 尽量在短时间内从同一网络连续请求。

Google Cloud CDN的故障排查文档同样建议使用 curl -s -D - -o /dev/null URL 查看响应头,并以 Age 等字段辅助确认缓存响应。

连续测试结果应该怎么判断?

下面几种模式比单次结果更有参考价值。

连续结果

常见解释

下一步

第一次 MISS,随后 HIT,Age增加

节点首次取回后成功缓存

再测试其他地区和关键资源

连续多次都是 MISS

对象未写入、缓存键变化、TTL过短或频繁淘汰

检查缓存头、规则、参数和日志

一直是 BYPASS 或 DYNAMIC

内容按规则未进入共享缓存

确认是业务设计还是配置错误

HIT,但Age偶尔归零

可能切换节点、清缓存、重新验证或重新填充

同时记录响应IP、节点和时间

一个地区 HIT,另一个地区 MISS

不同节点拥有独立缓存

各地区连续测试

外层显示 HIT,另一厂商字段显示 MISS

可能存在多层CDN或残留响应头

结合IP、CNAME和日志判断

浏览器显示 304

浏览器或中间缓存进行了条件验证

不能自动等同于CDN HIT

最理想的结果一定是“全部HIT”吗?

不是。

公开的版本化静态资源适合长期缓存,高命中通常是好事;但登录接口、个人资料、订单、购物车和实时权限数据,本来就不应该被不同用户共享缓存。

缓存优化的目标不是让所有URL变成 HIT,而是让应该缓存的内容稳定命中,不应该共享的内容始终保持隔离。

为什么CDN一直MISS?

如果同一个静态资源连续测试仍然 MISS,可以按下面顺序排查。

1. 响应本身不允许共享缓存

检查源站和CDN返回的:

Cache-Control: private
Cache-Control: no-store
Cache-Control: no-cache
Cache-Control: max-age=0
Set-Cookie: ...

这些字段的影响并不完全相同:

  • no-store 表示不应存储响应;

  • private 表示共享缓存不应存储,只可由私有缓存处理;

  • no-cache 并非“绝对不能存”,而是复用前需要验证;

  • max-age=0 会让响应立即变得不新鲜;

  • Set-Cookie 在部分CDN默认策略中会导致绕过缓存。

不要盲目删除这些头。先确认它们是否在保护用户状态和敏感内容。

2. 每次请求使用了不同的缓存键

常见原因包括:

  • URL查询参数变化;

  • Host 不同;

  • Cookie被纳入缓存键;

  • Authorization 请求被单独处理;

  • Accept-Encoding、语言或设备头参与缓存变化;

  • Vary 导致缓存被拆成多个版本。

Google Cloud CDN的缓存工作原理指出,URL、查询参数和被纳入缓存键的请求头都会影响对象能否复用。

一个页面看似请求同一文件,实际缓存键可能一直在变化。

3. 缓存规则没有覆盖这个URL

检查路径、扩展名、响应状态码和请求方法是否符合CDN规则。

常见情况是只缓存 .jpg、.css、.js,而实际文件使用了没有扩展名的动态路径;或者规则优先级被另一条“绕过缓存”配置覆盖。

4. TTL过短或对象被频繁淘汰

如果TTL只有几秒,下一次请求到达时对象可能已经过期。

冷门对象也可能因为节点容量策略被提前淘汰,因此缓存时间上限不等于保证驻留时间。

5. 每次访问的不是同一个节点

Anycast、DNS调度、多CDN和IPv4/IPv6差异,都可能让连续请求进入不同节点。

测试时可以同时记录远端IP:

curl -sS -D - -o /dev/null \
  -w 'remote_ip=%{remote_ip} total=%{time_total}\n' \
  https://www.example.com/assets/app.css

如果响应IP不断变化,Age和缓存状态重置就更容易解释。

6. 测试的是HTML、接口或带身份状态的请求

许多CDN默认缓存静态文件,却不默认缓存HTML和动态接口。此时持续 DYNAMIC 或 BYPASS 可能正是预期结果。

先拿已知可缓存的公共静态资源建立基准,再排查动态内容。

为什么不同地区看到的HIT、MISS和Age不一样?

CDN的缓存不是全球只有一份。

北京、新加坡、法兰克福和洛杉矶的用户可能进入不同的边缘节点,每个节点的访问热度、填充时间和淘汰状态都不同。

因此,同一个URL可能同时出现:

地区

缓存状态

Age

可能情况

北京

HIT

850

当地访问频繁,缓存较热

新加坡

HIT

42

最近刚填充或重新验证

法兰克福

MISS

无

该节点首次访问或对象已被淘汰

这并不矛盾,也不代表某个检测点出错。

可以先用 CdnChart网站测速 对同一URL做多地区测试,查看各地区的响应IP、耗时和访问差异,再结合自己用 curl、浏览器开发者工具或CDN日志取得的缓存响应头判断。

CdnChart的探测口径可以在测评方法说明中查看。

需要注意:一次跨地区测试仍然只是各节点当时的快照。要判断缓存是否稳定,最好固定URL,在相同地区连续测试,并记录时间、IP和缓存状态。

一次HIT不等于缓存命中率高

单次响应只能回答“这一次是否命中”,不能回答“网站整体缓存效果如何”。

CDN控制台里常见的命中率还可能分为:

  • 请求命中率:被缓存满足的请求数,占符合统计口径请求数的比例;

  • 字节命中率:由缓存提供的流量,占总传输字节数的比例。

例如,大量小图标命中,但几个大文件频繁回源,请求命中率可能很好看,字节命中率却不高。

反过来,一个大视频命中也可能显著抬高字节命中率。

此外,不同厂商对动态请求、错误响应、不可缓存请求和上层缓存命中的统计口径可能不同。跨厂商比较前,应先核对指标定义,不要只比较一个百分比。

真正值得长期观察的是:

  • 关键静态资源的请求命中率和字节命中率;

  • 回源请求数、回源流量与回源错误率;

  • 不同地区、路径和文件类型的命中差异;

  • 缓存清除、发布和版本更新后的变化;

  • 源站负载是否随命中提升而合理下降。

常见问题

第一次MISS、第二次HIT,说明CDN正常吗?

通常说明当前节点完成了缓存填充,是正常的冷缓存到热缓存过程。但仍需检查对象TTL、其他地区节点和长期命中率。

MISS是不是说明CDN加速没有生效?

不是。请求已经到达CDN,只是当前缓存层没有可复用对象。

CDN仍可能提供TLS终止、连接优化、安全防护或上层缓存等能力。

Age为0是HIT还是MISS?

只看 Age: 0 无法判断。它可能是一份刚写入或刚完成重新验证的缓存,也可能来自其他代理。

应同时查看厂商缓存状态头和日志。

Age越大是不是访问越慢?

不是。Age表示响应的缓存年龄,不是请求耗时。

性能要看DNS、连接、TLS、TTFB和总下载时间等指标。

Age超过max-age为什么还能收到内容?

可能发生了重新验证、允许返回stale内容、存在上层缓存策略,或者看到的 max-age 并非CDN最终采用的边缘TTL。

需要结合 s-maxage、CDN-Cache-Control、厂商配置和缓存状态分析。

浏览器强制刷新后变成MISS,配置坏了吗?

不一定。

强制刷新可能携带要求重新验证或绕过本地缓存的请求头,也可能触发不同的CDN处理。排查时应使用固定的普通GET请求,避免把浏览器缓存和CDN缓存混为一谈。

如何确认请求真的访问了源站?

查看源站访问日志、CDN回源日志和回源指标最可靠。

客户端的 MISS 可以提示你继续调查,但无法完整描述多层缓存内部发生了什么。

总结:缓存命中要看一组证据,不是一个单词

记住三个核心结论:

  1. HIT 表示当前缓存层找到了可复用对象,但只代表本次请求和当前节点;

  2. MISS 表示当前缓存层未命中,不等于CDN没生效,也不一定能证明每个请求都直达源站;

  3. Age 表示响应自生成或最近一次验证后经过的估算秒数,不是响应时间,也不是天然的剩余TTL。

实际排查时,选择一个公开静态资源,保持URL和请求条件不变,连续请求三次;同时记录缓存状态、Age、Cache-Control、响应IP和检测时间。

然后再换地区验证,并用CDN控制台或源站日志确认是否真正回源。

如果还不确定域名接入了哪家CDN,可以先使用 CdnChart CDN检测 查找厂商线索;如果想比较不同地区的访问节点和速度,可以使用 CdnChart网站测速。

把缓存响应头与多地区测速结果放在一起,远比看到一次 MISS 就下结论更可靠。

  • CDN怎么看是否命中缓存
  • CF-Cache-Status HIT什么意思
  • CDN一直MISS怎么办
  • Age响应头是什么意思

相关文章