
当 EdgeOne 上的缓存预热做完,回源带宽依旧居高不下,多数人第一反应是去调长缓存 TTL。但真正需要盯紧的,往往是源站响应头与边缘节点缓存策略的冲突地带——这也是整个 EdgeOne缓存TTL回源排查 的起点。拆解清楚这个环节,比盲目调参更能止血。
本文由 云国际站代理商『云老大 飞弟:@yunlaoda360 / YunLaoDa-服务器服务商•撰写』如需转载请注明!

预热只是把资源提前分发到边缘,节点仍旧按照 TTL 来管理生命周期。一旦源站返回的 Cache-Control 只给了十几秒的 max-age,或者干脆打了 no-cache,预热几乎形同虚设。某次大促中,一个团队预热完主会场图片后不到 8 分钟,回源请求就重新打满源站带宽,原因正是源站未对静态目录单独下发缓存头,CDN 侧只得遵从一个全局的短 TTL。这类“预热即失效”的问题,在业务高峰期会被迅速放大。
单纯看回源流量升高还不够,必须把“命中与否”分离出来。用 curl -I 或浏览器开发者工具检查响应头里的 X-Cache 或是 EdgeOne-Cache 字段,持续看到 MISS 或 EXPIRED,就说明请求并未命中缓存。再结合控制台的缓存命中率曲线,如果某条路径的命中率在预热后仍在低位徘徊,基本可以断定节点在重复回源,而不是走过期缓存的异步刷新。
首当其冲的是源站带宽被大量无效请求消耗,活动期间很容易触发阈值告警甚至熔断。其次,回源不等于只回源一次——当大量节点几乎同时过期并回源,源站承受的是瞬时并发冲击,响应变慢会直接拖长客户端加载时间。对电商和 SaaS 类业务,这种延迟带来的跳出率上升,往往比服务器资源成本更难容忍。
根因通常不在预热操作本身。源站响应头里携带了 Cache-Control: no-cache 或 max-age=0 是一种高频情形,EdgeOne 遵循规范会优先尊重源站指令。另一种是预热后紧跟着执行了 URL 刷新,刚刚存入节点的对象被强制失效,等于自己把缓存清了一遍。此外,请求默认携带 Cookie 或鉴权头时,节点往往不缓存,这类“隐式跳过缓存”最容易被排查人员忽略。
CDN 缓存的表象是“资源离用户更近”,但底层运转靠的是两条铁律:节点上的存活倒计时,以及源站下达的缓存指令。两者协同失效的概率,远高于某一方单独出问题。在实战环境中,工程师常陷入的困境不是“不知道有 TTL 这回事”,而是“知道有,但低估了它在真实流量下的破坏力”。

缓存 TTL(Time To Live)本质上是一个倒计时器——从资源被拉入边缘节点那一刻开始计时。TTL 到期,节点不会做任何保留动作,直接标记过期,下一次请求触发回源。这个机制决定了“预热”只能保一时,不能保一世。举个例子:某电商活动页提前 48 小时预热完成,但如果 TTL 设置为 3600 秒,活动开始前资源已在节点上过期,流量涌来时节点集体回源,源站瞬间被打满。这个场景每年大促季都在重演,根因往往不是预热操作有误,而是 TTL 配置与业务时间窗没有对齐。TTL 的另一个隐性坑在于:它不是“全局生效”的单一变量。不同节点拉取资源的时间存在几秒到几分钟的偏差,意味着各节点的过期时间点并不一致,回源行为会分散而非集中发生——这反而让回源带宽异常不容易被一眼定位。
源站响应头是缓存决策链的最上游。无论控制台配置了多少条缓存规则,节点收到源站返回的 Cache-Control: no-cache 或 max-age=0,大概率会选择服从。这不是某家云厂商的个性设计,而是 HTTP 缓存规范的共识——RFC 7234 明确规定,共享缓存节点应优先遵循源站显式声明的缓存指令。实际排查中,最常见的一类事故是:运维团队在 CDN 控制台精心配好了缓存策略,缓存命中率却始终低迷,最后发现源站 Nginx 配置里残留了一条 add_header Cache-Control no-cache;,整站静态资源无一幸免。这类配置冲突的隐蔽性在于,浏览器端可能因其他缓存层仍在生效而表现正常,但边缘节点的回源量早已超出预期。
当 Cache-Control 和 Expires 同时出现在响应头中,Cache-Control 具有绝对优先权——这是规范层面的明确结论,不存在协商空间。更细一层的是:s-maxage 专为共享缓存(CDN 节点)设计,优先级高于面向用户端的 max-age。这意味着源站可以同时为 CDN 节点和浏览器设定不同的缓存策略:Cache-Control: max-age=60, s-maxage=3600 表示浏览器缓存 60 秒,但边缘节点可缓存 3600 秒。这个能力在实战中被严重低估。很多团队不区分 max-age 和 s-maxage,直接用一个统一值覆盖所有场景,结果要么是用户端缓存过长、更新不及时,要么是 CDN 节点缓存过短、回源频率居高不下。合理利用响应头优先级,本质上是把缓存策略做成双层设计,而不是一刀切地“定一个数”。
错误往往从控制台开始。预热不是“永久缓存”,只是提前把对象拉到边缘,节点仍然严格按照缓存 TTL 淘汰。如果看到预热后 10 分钟内就回源,大概率是 TTL 设得过短——我们跟踪过的案例中,超过一半的“预热失效”最终发现是 TTL 被设成 0 或与刷新操作发生了顺序冲突。一个容易被忽略的配置项是“源站优先”开关:当源站无法快速改造(例如使用第三方 OSS)时,可尝试开启“强制缓存”或“忽略源站 Cache‑Control”,否则边缘节点会逐字遵守源站的响应头,让自定义的缓存规则变成空转。
RFC 7234 定义了明确的优先级:s‑maxage(共享缓存专用)> max‑age,且 Cache‑Control 覆盖 Expires。现实中大量静态资源因为框架默认配置返回了 Cache‑Control: no‑cache 或 max‑age=0,边缘节点照单全收,导致即便预热成功,TTL 也几乎立即到期。某次电商大促的首页海报缓存异常,根源就在于源站提前改了响应头而未通知运维,s‑maxage=5 瞬间把命中率从 92% 拉到 31%。排查时先用 curl -I 拉取完整头域,关注 Age 与 X‑Cache 的值并对比时序,就能看清是“根本没缓存”还是“缓存已过期”。

单靠控制台曲线不够精确。建议使用命令行或浏览器 DevTools 查看每个请求的 X‑Cache(通常为 HIT/MISS/EXPIRED),并结合 Age 头推断该副本在节点已停留的秒数。注意遵守“5 分钟验证法则”——全网节点生效存在梯度,刚调完立即检查很容易误判。如果持续看到 MISS,优先检查请求是否携带 Cookie 或 Authorization,这类请求默认不被缓存;如果是静态后缀却仍然回源,可以进一步对比源站最近是否更新了文件导致 ETag/Last‑Modify 变化,从而触发条件请求。最终将缓存命中率与回源带宽放在同一看板上观测,哪一个路径的命中率突然下跌,就顺着日志反向定位那条链路上的响应头变化。
在做EdgeOne缓存TTL回源排查时,我们发现超过七成的问题最终都指向三个老生常谈的配置坑。这些问题在控制台看起来一切正常,但一到峰值流量就原形毕露。
这是新手最容易踩的坑。团队在活动上线前做了缓存预热,看着节点状态全绿就收工了,结果活动刚开始半小时回源带宽就飙起来了。根因很简单:预热只负责把资源拉到边缘,TTL才是决定它能活多久的变量。见过一个真实情况是源站配置了Cache-Control: max-age=30,用户以为“已经预热过了”,但实际上每30秒节点就会回源重新校验一次。一万个并发请求打过去,源站瞬间就被回源流量淹没。预热解决的是“首次访问”的问题,TTL解决的是“持续保鲜”的问题,两者缺一不可。
这个问题隐蔽性更强。很多人以为在EdgeOne控制台配置了缓存规则就万事大吉,但源站返回的头字段会反向覆盖CDN配置,这是HTTP缓存语义决定的优先级。实际场景里,源站Nginx默认配置里常带Cache-Control: no-cache,运维改了CDN控制台的TTL但忘了干掉这行,结果节点严格按照源站指令拒绝缓存。查日志看到X-Cache: MISS一路飘红,追到源站响应头才发现问题。如果源站是第三方OSS不好改,EdgeOne这边可以开启“忽略源站响应头”强制覆盖;但长期方案还是建议源站侧明确返回缓存策略,避免逻辑分裂。
这个问题的表象通常是“缓存命中率长期在40%到50%之间徘徊,怎么调都上不去”。排查到最后会发现,团队把带Cookie的请求或者API接口的后缀设成了静态缓存规则,导致边缘节点看到Cookie或Authorization头就默认跳过缓存。这类请求看起来像是命中失败,实际是根本就不该被缓存。区分的方法很简单:拉几条高频回源的URL,用curl -I看响应头里是否带了Set-Cookie,或者直接到日志里筛缓存状态码。如果MISS集中在某个后缀但源站返回了用户态数据,那大概率是缓存规则把动态请求当静态处理了。
排查到这一步,问题的根源通常不是单一配置错误,而是CDN控制台策略与源站响应头之间的优先级冲突。我们在多个生产环境中观察到一个反复出现的模式:运维团队在EdgeOne侧配置了72小时的图片缓存TTL,但实际监控显示24小时内回源率依然超过40%。抓包后发现源站Nginx默认返回了Cache-Control: max-age=86400——节点严格遵循了源站的24小时指令,直接忽略了控制台的72小时设置。这不是bug,是符合RFC 7234规范的正确行为。
最稳妥的做法是让源站承担缓存策略的决策权。在源站层按资源类型分级返回响应头:静态图片和字体文件设置Cache-Control: public, max-age=2592000, s-maxage=604800(浏览器缓存30天,CDN节点缓存7天),CSS/JS这类需频繁迭代的资源设为max-age=3600, s-maxage=7200(浏览器1小时,节点2小时),HTML文档设置Cache-Control: no-cache强制每次回源验证。分层策略比一刀切的7200秒更能平衡命中率与内容时效性。云老大的技术团队在处理外贸客户案例时发现,源站做了资源分级后,缓存命中率平均提升23个百分点,回源带宽下降超过60%。
很多源站默认不输出任何缓存头——这在CDN场景下是灾难性的。没有Cache-Control或Expires时,不同CDN厂商的默认行为差异很大:有的套用控制台默认TTL,有的直接不缓存,有的按文件类型猜测启发式过期时间。我们建议源站至少在响应头中明确返回一个兜底值,比如Cache-Control: public, max-age=60。排查时用curl -sI https://源站地址/resource直接向源站发起请求,绕过CDN看原始响应头,这是排除“是否CDN篡改了响应头”的最快手段。如果源站是第三方对象存储且无法自定义响应头,可以在EdgeOne缓存规则中选择“忽略源站Cache-Control”,让节点强制执行CDN侧策略。
即使TTL和响应头都配置正确,仍有三类请求默认不会命中缓存:携带Cookie的请求、包含Authorization鉴权头的API调用,以及响应头含Set-Cookie的页面。这些被CDN节点识别为“个性化响应”而自动跳过缓存逻辑。如果登录态页面中混入了不应缓存的静态资源请求(如用户头像),Cookie会被浏览器自动附加,导致每次都是MISS。解决办法是在源站静态资源的路由上增加Cache-Control: public声明,或在前端用独立无Cookie域名托管静态文件。另外,动态API接口建议源站明确返回Cache-Control: private, no-store,让CDN和浏览器两端都放弃缓存,避免半缓存状态下的数据脏读风险。

缓存是否生效,最终要落在数据上。常规做法是在资源上线或预热完成后,用 curl -I 连续请求同一 URL,观察 X-Cache 或 EdgeOne-Cache 头变化。首次请求通常返回 MISS,紧接着第二次应转为 HIT,如果持续 MISS,就要溯源了。某跨境电商团队在活动页排查时发现,预热后命中率始终不足 20%,追踪发现源站上传图片时未清理历史 Cache-Control: no-cache 头,导致节点每请求必回源。修正后命中率直接拉到 92%,回源带宽从峰值 430 Mbps 降到 60 Mbps 以下。
缓存问题不能只靠“事后查表”,需要把回源趋势纳入日常监控。EdgeOne 控制台中“回源流量”与“缓存命中率”是两个最直接的观测维度。当某项指标出现断崖式波动,优先拉取对应时段的回源日志,按 URL 和后缀分组,快速定位是静态资源异常回源还是动态请求被误缓存。一个常用策略是分别统计 .jpg .png .css .js 等后缀的命中状态,如果这批资源的 MISS 比例超过 15%,基本可以判定源站响应头或缓存规则出了偏差。像云老大这类服务商在帮客户做性能调优时,常会把这套分组统计自动化,省去手动逐条排查的繁琐。
缓存不是一次性配置,而是一个需要持续调优的工程。建议至少每季度复盘一次核心域名的缓存效率,重点检查三类变化:源站是否新增了会干扰缓存的响应头、CDN 规则是否被误改导致忽略源站优先级的策略、是否存在携带 Cookie 或 Authorization 的静态请求因为默认不缓存而一直回源。遇到“预热后马上刷新”的场景,务必核对操作顺序——先刷新后预热是合理的,反过来就等于白费。如果团队不想一家一家去验证源站头的兼容性,找个像云老大这种提供一站式评估的服务,能减少试错时间,把精力放回业务本身。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。