技术知识文章集合TECHNICAL ARCHIVE · 457 DOCUMENTS

显示模式

登录
ARCHIVE DOCUMENTETC

关于 CDN、回源等问题一网打尽

所属馆藏
Other
文件格式
Markdown
原始路径
Other/06-关于 cdn、回源等问题一网打尽
本文目录9 个章节
  1. 文章目录
  2. 一、访问 CDN 资源和不通过 CDN 访问的过程有什么不同
  3. 二、回源是什么意思?
  4. 三、除了静态资源,API 是否可以缓存?
  5. 四、资源的新鲜度如何判定?CDN 如何更新数据?
  6. 五、几个专业术语
  7. 六、排查 CDN 和回源问题
  8. 总结
  9. 参考资料

关于 CDN、回源等问题一网打尽

Category(分类): Other Status: 未知

本文保留原文关于 CDN 访问流程、回源、API 缓存、资源过期和专业术语的结构,并结合 HTTP 缓存规范和当前 CDN 产品实践修订容易误解的说法。

原文发表于较早时期,文中的全局负载均衡、区域负载均衡和 CDN 节点图是典型的教学模型。现代 CDN 可能使用 DNS 调度、Anycast、分层缓存、边缘函数或多种机制组合,并不一定完全按图中的设备名称实现。

复盘日常问题时,看到了曾经听到后端同学讨论“回源”的场景。一直以来我对 CDN 相关知识也一知半解,借此机会把访问流程、缓存、回源和动态内容重新梳理一遍。

文章目录

  • 访问 CDN 资源和不通过 CDN 访问的过程有什么不同;
  • 回源是什么意思,什么时候会回源;
  • 除了静态资源,API 是否可以缓存;
  • 资源的新鲜度如何判定,CDN 如何更新数据;
  • CDN 常见专业术语和排查方法。

一、访问 CDN 资源和不通过 CDN 访问的过程有什么不同

不通过 CDN 的简化过程

用户访问源站时,通常是:

浏览器/系统缓存
    -> stub resolver
    -> 递归 DNS 解析器
    -> 解析 A/AAAA/CNAME 等记录
    -> 与源站建立 TCP/TLS 或 QUIC 连接
    -> 源站处理 HTTP 请求并返回响应

DNS 解析器可能命中缓存,也可能代表客户端从根、顶级域和权威 DNS 查询。DNS 解析完成后,客户端拿到的是一个或多个地址;它还要经过连接建立、TLS 握手、HTTP 请求、源站排队和业务处理,才能得到最终内容。

使用 CDN 的典型过程

原文用了一张流程图说明 CDN 访问过程:

访问 CDN 资源的典型流程

一个更准确的简化过程如下:

  1. 浏览器、操作系统和 stub resolver 先检查本地缓存、hosts 文件和连接复用状态;
  2. 如果没有可用 DNS 结果,客户端向配置的递归 DNS 解析器查询业务域名;
  3. 业务域名可能通过 CNAME 指向 CDN 服务商提供的接入域名。递归解析器会继续解析 CNAME 链,直到得到 A/AAAA 地址或其他可用接入信息;
  4. CDN 的权威 DNS、Anycast 或全局流量调度系统根据解析器位置、网络线路、节点健康、容量和策略返回合适的接入地址;
  5. 客户端使用原始域名建立 HTTPS 上的 HTTP/2 或 HTTP/3 连接。TLS SNI 和 HTTP Host(HTTP/2、HTTP/3 中对应 :authority)仍然是用户访问的业务域名,而不是简单替换成 CDN 的 CNAME 文本;
  6. CDN 边缘节点根据 Host、路径、查询参数、请求头和缓存配置进行路由与缓存查找;
  7. 如果缓存命中且仍然新鲜,边缘节点直接返回响应;如果未命中、已过期、被绕过或需要验证,则按配置回源;
  8. CDN 将源站响应返回客户端,并可能保存一份边缘缓存供后续请求使用。

原文中有几个需要修正的地方:

  • 客户端并不一定直接拿到“全局负载均衡系统的 IP”。DNS 可能返回 CDN Anycast 地址、边缘入口地址或另一层 CNAME;具体由服务商架构决定;
  • DNS 查询中通常只有域名和记录类型,不包含完整 URL 的路径。像 /images/logo.png 这样的路径要到 HTTP 请求到达 CDN 后,才由边缘层处理;
  • 因此,DNS 调度通常不能直接根据完整 URL 路径选择缓存服务器,路径和缓存键一般由 CDN 的 HTTP 层处理;
  • “距离最近”只是便于理解的说法,实际还会综合递归解析器位置、运营商、网络拓扑、节点健康和容量;
  • CNAME 是 DNS 名称的别名,不是 HTTP 重定向,也不是把文件从一个地址复制到另一个地址。

CNAME 的解析过程

假设用户访问:

https://static.example.com/app.js

DNS 可能配置为:

static.example.com CNAME customer.cdn.example.net

递归解析器会继续查询 customer.cdn.example.net 的 A/AAAA 或其他记录,然后把结果返回给客户端。客户端通常不会感知“先解析了业务域名、再解析 CDN 域名”的内部细节。

传统 DNS 中,CNAME 的目标必须是域名而不是直接写 IP,且同一个名称通常不能同时拥有 CNAME 和其他类型的记录。根域名是否支持 CNAME,要看 DNS 服务商提供的 ALIAS、ANAME 或 CNAME flattening 能力,不能把子域名的配置方式直接套到根域名。

CDN 像“家门口的小卖部”,但不只是仓库

原文用康师傅泡面作比喻:如果家门口没有小卖部,就要去工厂拿;有了小卖部,就可以去附近且有货的小卖部拿。这个比喻可以帮助理解边缘缓存:

  • 源站像生产和存放内容的工厂;
  • CDN 边缘节点像分布在不同区域的仓库或小卖部;
  • 缓存命中时,用户直接从边缘获取;
  • 缓存未命中时,边缘需要向源站或上一级缓存取货;
  • “附近”不只由地理距离决定,还取决于网络路径、负载和服务策略。

CDN 也不一定把资源预先复制到每个节点。许多 CDN 采用按请求回填的 pull/cache-fill 模式,热门资源才会逐渐在相应节点形成缓存。

二、回源是什么意思?

**回源(origin fetch/back-to-origin)**是指 CDN 边缘节点无法直接用本地缓存满足请求,于是向源站或上一级缓存发起请求,获取资源或验证已有资源的过程。

一个典型的多级缓存结构可能是:

客户端
  -> 边缘节点
  -> 区域缓存/父节点/Origin Shield(如果产品启用)
  -> 源站

并不是所有 CDN 都有独立的区域缓存或 Origin Shield。有的边缘节点会直接访问源站,有的会先访问服务商配置的父缓存,以减少多个边缘节点同时回源造成的压力。

哪些情况会回源?

常见原因包括:

  • 边缘节点从未缓存过该资源,发生 cache MISS;
  • 资源已超过新鲜时间(TTL),需要重新获取或验证;
  • 资源被主动 purge/invalidate;
  • 请求命中缓存绕过规则,例如带登录态、Cookie、Authorization 或特定请求头;
  • 源站响应了 Cache-Control: no-storeprivate 或其他不允许共享缓存的指令;
  • 缓存键发生变化,例如查询参数、Host、编码协商或自定义请求头不同;
  • 当前请求方法、状态码、Range 或响应头不符合 CDN 的缓存策略;
  • 节点因为容量淘汰、重启或故障没有保留原来的对象。

回源不一定意味着“缓存里完全没有文件”。已有缓存过期后,CDN 可能携带 If-None-MatchIf-Modified-Since 向源站重新验证;源站返回 304 Not Modified 时,CDN 可以继续使用原来的响应,而不必重新传输完整内容。

回源流程示例

客户端请求 /assets/app.js
        |
        v
边缘节点查缓存
        |
   +----+----+
   |         |
  HIT       MISS/过期/绕过
   |         |
直接响应   请求父缓存或源站
             |
        +----+----+
        |         |
      304       200 新内容
        |         |
   使用旧对象   保存并返回

回源次数和回源流量是 CDN 监控中的重要指标。即使用户侧响应很快,MISS 比例过高也可能让源站在流量高峰时承受很大压力。

如何减少不必要的回源?

  • 给带内容哈希或版本号的静态资源设置合理的长 TTL;
  • 使用稳定、可预期的缓存键,避免无意义的查询参数拆分缓存;
  • 给 HTML、API 和静态资源设置不同缓存策略;
  • 为高频热点配置 Origin Shield、Tiered Cache 或请求合并(具体看服务商能力);
  • 为响应提供 ETagLast-Modified,支持条件请求;
  • 发布时优先使用新文件名,少依赖全站 purge;
  • 监控 HIT、MISS、BYPASS、回源状态码、回源延迟和源站带宽。

三、除了静态资源,API 是否可以缓存?

先区分两个概念:API 缓存动态加速不是同一件事。

  • 缓存加速:边缘保存一个响应,后续请求可以直接复用;
  • 动态加速:内容仍然由源站实时生成,CDN 主要优化 DNS、路由、连接复用、TCP/TLS/QUIC 链路或边缘到源站的网络路径,不一定保存响应正文。

原文观点需要修正

原文认为 API 经常更新、可能关联用户信息,而且 CDN 主要依靠 URL 判断缓存,因此 API 不适合放到 CDN。这个结论过于绝对:

  • CDN 和 HTTP 缓存通常默认更容易缓存 GETHEAD 响应,但并不是“只有 URL 能决定缓存”,缓存至少需要考虑请求方法和目标 URI,还可能结合 Vary 指定的请求头、Cookie、Authorization、查询参数以及 CDN 自定义缓存键;
  • POST 等方法通常不会被普通 CDN 默认缓存,但 HTTP 规范并没有把“所有 API 永远不能缓存”作为规则。只有在 API 明确允许、响应可复用且缓存系统支持时,才应考虑缓存;
  • API 是否适合缓存,关键不是“它是不是 API”,而是响应是否可以在多个用户之间安全复用、是否允许一定时间的旧数据,以及是否能正确表达缓存策略。

适合缓存的 API

下面这些 API 在设计清楚缓存语义后可以使用 CDN:

  • 公共排行榜、公开文章列表、商品目录、地区配置;
  • 不包含用户身份信息的搜索建议或公共元数据;
  • 更新不频繁、允许几秒到几分钟延迟的 GET 接口;
  • 公开的 JSON 配置、版本信息和静态化数据。

示例:

GET /api/public/config HTTP/1.1
Host: api.example.com

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: public, max-age=30, s-maxage=300
ETag: "config-v17"
Vary: Accept-Encoding

这里可以让浏览器缓存 30 秒,让共享 CDN 缓存 300 秒。具体 TTL 要根据数据更新频率和业务容忍度决定。

不适合直接共享缓存的 API

以下内容不能未经设计就放到共享 CDN 缓存:

  • 用户订单、账户、私信、购物车和权限信息;
  • 依赖 Cookie、Authorization 或用户 ID 的响应;
  • 一次性验证码、支付状态和带签名的私有下载地址;
  • 可能把一个用户响应返回给另一个用户的接口;
  • 对实时一致性要求很高的写后读场景。

可以使用:

Cache-Control: private, no-cache

这表示响应可以存在于用户私有缓存中,但不能由共享 CDN 直接复用,使用前需要验证。对确实不应被任何缓存存储的数据,可以使用:

Cache-Control: no-store

如果一个带 Authorization 的响应确实要允许共享缓存,必须明确设置 publics-maxage 或其他符合规范和 CDN 文档的策略,并确保缓存键包含所有影响响应的因素。默认情况下不应这样做。

API 缓存的安全检查

设计 API CDN 缓存时,至少检查:

  1. 请求是否为可安全复用的 GET/HEAD,是否有必要支持其他方法;
  2. 响应是否包含用户身份、Cookie、Authorization 或敏感头;
  3. 缓存键是否包含真正影响响应的 Host、路径、查询参数和协商请求头;
  4. VaryCache-ControlSet-Cookie 是否与 CDN 的实际规则一致;
  5. 是否需要忽略某些查询参数,是否会导致缓存投毒或绕过鉴权;
  6. 是否设置了合理的 TTL、主动刷新、版本号和故障时过期策略;
  7. 是否用不同用户、不同权限和不同地区进行回归测试。

不要仅仅看到响应状态码是 200 就让 CDN 缓存。缓存安全事故通常不是“CDN 把文件放错机器”,而是缓存键、鉴权和响应策略设计错误。

四、资源的新鲜度如何判定?CDN 如何更新数据?

资源何时算新鲜或过期?

资源是否新鲜,首先由源站响应头和 CDN 的缓存配置共同决定。常见响应头包括:

Cache-Control: public, max-age=300, s-maxage=3600
ETag: "asset-v42"
Last-Modified: Wed, 01 Jan 2025 00:00:00 GMT

常见规则:

  • max-age 通常控制一般缓存的 freshness lifetime;
  • s-maxage 专门控制共享缓存(如 CDN),通常优先于 max-age
  • Expires 是较早的绝对时间写法,现代配置更常使用 Cache-Control
  • ETagLast-Modified 用于过期后的条件验证;
  • no-cache 不是禁止存储,而是复用前必须验证;
  • no-store 表示不应存储响应;
  • private 表示响应不应被共享缓存复用;
  • stale-while-revalidatestale-if-error 可以在 CDN 支持时控制短暂提供旧内容和源站故障时的容错。

CDN 控制台的 Edge TTL、源站响应头、Surrogate-ControlCDN-Cache-Control 可能共同决定边缘缓存时间。不同厂商的优先级和默认行为不完全相同,不能只看某一条响应头就断言最终 TTL。

被动更新:Pull / Cache Fill

Pull 是最常见的 CDN 缓存方式:

  1. 客户端请求边缘节点;
  2. 边缘节点发现 MISS 或需要重新验证;
  3. CDN 向源站或上一级缓存请求内容;
  4. CDN 把响应返回客户端,并按策略保存缓存;
  5. 后续请求在 TTL 有效期内可以直接命中。

Pull 并不代表“源站主动把文件推送到每个节点”,而是第一次访问或刷新后由 CDN 按需拉取。多个用户同时请求冷资源时,部分 CDN 会使用请求合并,避免同一时刻大量重复回源。

主动更新:Purge、预热和厂商 Push

原文把主动更新称为 PUSH,但这个词在不同 CDN 中含义不统一,不能和 HTTP/2 Server Push 混为一谈。常见的主动操作有:

  • Purge/Invalidate:删除或标记 CDN 上的旧对象,使后续请求重新获取;
  • 预热/Prefetch/Preload:在大促或发布前主动让指定 URL 在部分或多个节点形成缓存;
  • 上传式 Push:某些厂商允许通过 API 或控制台把文件送入 CDN/对象存储;
  • 版本化发布:直接使用新文件名,让新旧资源通过不同 URL 并存。

主动 purge 不等于把新内容同步到每一个节点。不同服务商的 purge 生效范围、速度、限额和按 URL/目录/标签清理能力不同;清理后再次请求通常还会经历一次 MISS 和回源。

静态资源最稳妥的发布方式通常是“内容哈希文件名 + 长缓存”,例如:

app.8f3c1.js
app.1a92d.css

更新内容时生成新 URL,而不是覆盖原来的 URL。HTML 入口可以使用较短 TTL,并在发布流程中按需刷新;否则旧 HTML 可能继续引用旧资源。

304 Not Modified 和重新验证

过期对象不一定要完整下载。CDN 可以携带验证头回源:

If-None-Match: "asset-v42"
If-Modified-Since: Wed, 01 Jan 2025 00:00:00 GMT

如果源站确认内容没有变化,可以返回:

304 Not Modified

CDN 随后继续使用已有对象,并更新它的新鲜状态。若内容已经变化,源站返回新的 200 响应,CDN 再按规则替换缓存。

如何观察 CDN 是否真的更新?

可以查看响应头和服务商日志:

# 只查看响应头;HEAD 行为可能和 GET 有差异
curl -I https://static.example.com/app.8f3c1.js

# 用 GET 获取响应头但丢弃响应体,更接近真实访问
curl -sS -D - -o /dev/null https://static.example.com/app.8f3c1.js

常见的状态有 HITMISSBYPASSEXPIREDREVALIDATEDUPDATING 等,但具体名称由 CDN 厂商决定。例如 Cloudflare 使用 CF-Cache-Status,其他 CDN 可能使用 X-Cache 或自定义字段。不能跨服务商直接比较这些状态名的含义。

五、几个专业术语

边缘节点(Edge Node)

指接近用户网络接入位置、负责接收请求并提供缓存或代理服务的节点。它不一定是物理距离最近的机器,而是 CDN 根据网络、调度和健康策略选出的合适入口。

源站(Origin)

真正提供内容、动态计算结果或对象数据的服务器、对象存储、负载均衡器或应用平台。CDN 只是在源站前面提供缓存和代理能力,不能替代源站的业务逻辑。

回源 Host(Origin Host)

CDN 连接源站时发送的 HTTP Host 请求头。它可能与用户访问的 Host 不同,用于选择源站上的虚拟主机:

连接地址:203.0.113.10
回源 Host:www.origin.example.com

如果回源使用 HTTPS,还要检查回源 SNI、证书校验名和端口。只修改 Host 不一定能解决 TLS 证书不匹配。

回源协议(Origin Protocol)

指 CDN 到源站之间使用的 HTTP/HTTPS 和版本。客户端使用 HTTP/3,并不意味着 CDN 到源站也必须使用 HTTP/3;CDN 可以在边缘终止 HTTP/3,再用 HTTP/2 或 HTTP/1.1 回源。

对于登录、Cookie、管理接口和个人数据,通常应使用 HTTPS 回源,并验证源站证书,避免 CDN 到源站之间降级为明文 HTTP。

缓存键(Cache Key)

CDN 用来区分缓存对象的输入集合。至少通常包含请求方法和目标 URI,实际还可能包含:

  • Host 和路径;
  • 查询参数;
  • Vary 指定的请求头;
  • Accept-Encoding、语言、设备类型等协商信息;
  • Cookie、Authorization 或 CDN 自定义字段;
  • 服务商配置的忽略、排序或归一化规则。

缓存键过于细会导致命中率低,过于粗会把不同用户或不同版本的响应混在一起。调整查询参数规则前一定要做安全测试。

TTL、Freshness 和 Stale

  • TTL/Freshness lifetime:对象可以无需验证而复用的时间;
  • Fresh:在新鲜时间内,可以直接使用;
  • Stale/Expired:超过新鲜时间,通常需要回源验证或重新获取;
  • stale-while-revalidate:部分 CDN 可以在后台验证期间短暂提供旧内容;
  • stale-if-error:源站失败时,部分 CDN 可以在允许窗口内提供旧内容。

对象过期不一定马上从磁盘删除,它也可能保留并等待重新验证,或者因空间不足提前淘汰。

GSLB、Anycast 和分层缓存

  • GSLB(Global Server Load Balancing):全局流量调度的泛称,可能由 DNS、Anycast、HTTP 调度或多种机制组合完成;
  • Anycast:多个网络位置宣告相同地址前缀,由路由系统选择网络层面的入口;
  • Tiered Cache/Origin Shield:在边缘节点和源站之间增加父缓存或保护层,减少大量边缘节点同时回源。

这些词描述的是架构能力,不代表所有 CDN 都有同名、同位置的独立设备。

动态加速

动态加速通常不以缓存响应为主要手段,而是通过 DNS 调度、网络路径优化、连接复用、TCP/TLS/QUIC 优化、请求合并或边缘接入减少动态请求到源站的延迟。

动态加速不能把数据库查询结果自动变成静态缓存,也不等于 API 一定可以共享缓存。业务仍然需要正确处理鉴权、连接、超时和源站性能。

六、排查 CDN 和回源问题

DNS 层

dig static.example.com CNAME
dig static.example.com A
dig static.example.com AAAA

检查 CNAME 是否指向预期、A/AAAA 是否存在、TTL 是否符合预期。不同递归解析器、不同运营商和不同地区可能得到不同结果,不要只用一台机器判断全球情况。

HTTP 和缓存层

curl -sS -D - -o /dev/null https://static.example.com/assets/app.js
curl -v https://static.example.com/assets/app.js -o /dev/null

重点观察:

  • Cache-ControlAgeETagLast-Modified
  • CDN 的 HIT/MISS/BYPASS 状态;
  • ViaX-CacheCF-Cache-Status 等厂商头;
  • Set-CookieVaryAuthorization 是否导致绕过;
  • HTTPS 证书、SNI、Host 和重定向是否正确。

源站和回源层

  • 直接请求源站是否返回正确 Host 对应的站点;
  • CDN 到源站的端口、协议和证书是否匹配;
  • 源站是否限制了 CDN 出口 IP;
  • 回源状态码、连接超时和 TLS 握手是否异常;
  • 是否由于缓存键或查询参数导致命中率过低;
  • purge 后的首次请求是否正常回源并生成新缓存。

总结

CDN 的核心不是“把资源简单放到离用户最近的服务器”,而是由 DNS/Anycast 调度、边缘代理、缓存键、HTTP 缓存语义、回源链路和源站保护共同组成的分布式系统。

理解本文可以抓住这些重点:

  • DNS 负责把业务域名引入 CDN 接入链路,URL 路径要到 HTTP 层才会参与缓存和路由;
  • CNAME 是 DNS 别名,不是 HTTP 重定向;
  • 回源可能发生在 MISS、过期、验证、绕过规则、主动刷新和节点淘汰等场景;
  • API 不一定不能缓存,公开、可复用且允许短暂旧数据的 API 可以按规范缓存;
  • 用户私有响应必须防止被共享 CDN 复用,privateno-store、Authorization 和 Cookie 需要谨慎配置;
  • TTL、Cache-ControlETagLast-Modified 和 purge/版本化发布共同决定资源更新方式;
  • Pull 是按需回填,Push、预热和 purge 是不同的厂商能力,不能混为一谈;
  • CDN、DNS、TLS、缓存、回源和源站需要分层监控,出现问题时应先确定故障所在层。

参考资料

457 DOCUMENTS · 10 COLLECTIONS
ARCHIVE SEARCH457 篇文章

SEARCH GUIDE

输入关键词开始搜索

支持搜索文章标题、所属分类和原始文档路径。

按分类浏览

10 COLLECTIONS