CDN加速原理详解:从DNS调度到缓存回源,一次请求到底走了哪几步
同一个页面,为什么有人秒开有人转圈
把网站部署在一台服务器上,看起来是最简单也最直观的方案:代码、数据库、图片全在一处,逻辑清晰。但只要用户分布在不同城市、不同运营商、甚至不同国家,这套方案的短板就会立刻暴露——物理距离带来往返时延,跨网互联带来额外跳数与拥塞,国际出口的带宽瓶颈更是让加载时间成倍增长。用户点下回车,浏览器要做的第一件事是找到服务器,可这一找,可能就要跨越大半个中国。
CDN(内容分发网络)解决的正是这一段路程。它的思路并不复杂,甚至可以说是"反向"的:既然用户不愿意跑远路去找服务器,那就把内容提前搬到离用户近的地方去。但真正落到工程实现上,从用户敲下域名到页面渲染完成,中间发生了一系列相当精巧的调度、缓存与传输优化。把这些环节讲清楚,也就讲清楚了「cdn加速原理」。
CDN 本质上是一层插在源站前面的分布式代理缓存
理解 CDN,最忌讳把它当成什么玄学黑科技。它不改变网站的业务逻辑,不修改页面的 HTML 结构,它只是在"用户"和"源站"之间,插了一层分布在各处的节点,把原本一条很长的链路拆成了两段:用户到就近节点,节点到源站。而第二段通常只在节点上没有这份内容的时候才会发生。
从用户的视角看,域名没变、访问地址没变、浏览器地址栏里的一切都和以前一样;从源站的视角看,外部访问量大幅下降,回源带宽明显减少,CPU 和数据库压力被"卸"掉了一大块。这中间的身份替换,发生在域名解析和 HTTP 请求两个层面。
第一步:把用户"引"到最近的节点
DNS 调度决定了一切
在传统部署中,一个域名对应一个固定 IP,全球用户都去敲同一扇门。接入 CDN 后,网站域名通常以 CNAME 的方式指向服务商提供的调度域名,由 CDN 的权威 DNS 在应答解析请求时,根据解析来源、线路归属、节点健康状态和实时负载,返回一个"当前最合适"的节点 IP。
这里有个容易被忽略的细节:调度系统看到的往往不是用户的真实 IP,而是用户所使用的递归 DNS 服务器的出口 IP。于是同一个城市的两名用户,可能因为各自配置了不同的 DNS,被分配到相距上千公里的两个节点上。这也是为什么接入 CDN 之后,用不同网络环境测速,结果差异有时大得离谱。
HTTPDNS 与 Anycast 补位
为了绕开递归 DNS 可能带来的位置误判,一些应用会在客户端内置 HTTPDNS,直接向调度接口请求节点 IP,避开本地 DNS 的缓存和转发链路。另一条路径是 Anycast:同一个 IP 地址在多个机房同时宣告,由路由协议把数据包自然带到拓扑上最近的一处。两种方式各有取舍,实践中常与常规 DNS 调度混用。
第二步:节点如何判断"这份内容我有没有"
缓存键:命中率的隐形开关
用户被引导到节点后,节点并不会立刻去找源站,而是先用缓存键在本地查一遍。缓存键通常由完整 URL(包含查询参数)构成,部分场景还会把请求头中的某些字段、设备类型纳入维度。这一步的设计直接决定了命中率的高低。
一个非常典型的坑是缓存键被"撑爆":URL 里带着随机数时间戳、每次请求都不同的签名参数、或者参数顺序前后不一致,都会让本来完全相同的资源被识别成成百上千个不同的缓存对象。节点上看似存满了东西,实际每个都只被访问过一次,命中率自然上不去,加速效果也就无从谈起。做参数排序、剔除无效参数、把真正影响内容的参数白名单化,是接入 CDN 时最值得先做的一件小事。
TTL、新鲜度与协商缓存
缓存不是永久的。响应头里的 Cache-Control 决定了一份副本能"新鲜"多久,在有效期内,节点直接返回本地内容,根本不去打扰源站;过期之后,节点会带着 If-None-Match 或 If-Modified-Since 向源站做一次条件请求,源站确认内容未变时返回 304,节点只需更新元数据,继续使用旧副本。
这套协商缓存机制是节省回源带宽的关键,但前提是源站要正确返回 ETag 或 Last-Modified。很多站点依赖后端框架的默认行为,返回的内容明明没变,标识却在每次请求时都变化,结果就是每次协商都变成一次完整下载。
不同类型的资源需要不同的策略:带哈希指纹的 JS、CSS、字体、图片可以设置很长的缓存时间,因为文件名一变就等于换了一个新资源;HTML 页面变化频繁,适合较短的缓存时间配合协商缓存;接口数据则要结合业务对实时性的要求单独判断,必要时通过缓存键区分用户维度。
多级缓存与父层回源
边缘节点未命中时,请求并不会直接冲向源站。多数 CDN 会在边缘与源站之间设置父层缓存(也称中间源、二级节点),边缘先向父层询问,父层命中就直接返回,父层也没命中才由它代表下层去回源。这样一个原本可能由几百个边缘节点同时发起的回源请求,被收敛成少数几次,源站不会因为某个内容突然走红而被瞬间压垮。
第三步:让数据跑得更快,不只是"离得近"
回源链路的专线化
距离近只是加速的一半。节点与源站之间的这一段,走公网普通路由时同样会遇到拥塞节点和国际出口瓶颈。成熟的 CDN 会把这段链路放到专线或经过优化的骨干路径上,避开常见的拥堵点,让回源本身的耗时也降下来。
连接复用与协议升级
节点与源站之间维持长连接,意味着一次回源不必重新经历 TCP 三次握手和慢启动;TLS 会话复用、TLS 1.3 的 0-RTT 握手,把加密协商的开销压到最低;HTTP/2 的多路复用让同一连接上并行传输多个资源,避免了队头阻塞;在移动网络这类丢包率较高的场景下,基于 UDP 的 QUIC 往往比传统 TCP 表现更稳定。这些优化单看都不起眼,叠加起来对首字节时间的改善却相当可观。
从"传得快"到"传得少"
还有一类优化做的是减法:Brotli 或 Gzip 压缩文本资源,把 HTML、CSS、JS 的体积压缩到原来的几分之一;图片根据浏览器能力自动转换为 WebP 或 AVIF,并按需裁剪缩放。传输的字节数少了,无论链路多快,用户等待的时间都会缩短。这部分能力通常由 CDN 的增值功能提供,开启前需要评估压缩带来的 CPU 开销与内容类型是否匹配。
把整条链路串起来:一次访问的完整旅程
现在可以完整复盘一遍了。用户在浏览器输入网址后,本地 DNS 逐级查询,最终由 CDN 的调度系统返回一个就近节点的 IP;浏览器与该节点建立连接,完成 TLS 握手;节点收到 HTTP 请求,提取缓存键并检查本地副本——如果命中且未过期,内容立刻返回,整个过程连源站的影子都没见到;如果已过期,节点发起条件请求,源站返回 304,节点刷新元数据后继续使用旧副本;如果完全未命中,节点向父层询问,父层也没有,才由其回源获取内容,并在返回路径上逐层写入缓存,供后续请求直接复用。
整条链路中,真正落到源站身上的请求只是极小一部分,其余全被各层节点消化掉了。这就是 CDN 加速的基本盘:它优化的是"重复分发"和"长距离传输",而不是计算本身。
哪些因素真正决定加速效果
市面上提供 CDN 服务的厂商不少,国内的阿里云 CDN、腾讯云 CDN,以及国际上的 Cloudflare,在节点覆盖和功能细节上各有侧重。但无论选哪一家,最终效果都取决于几个共同变量:
- 缓存命中率——这是最核心的指标。命中率低,意味着请求不断穿透到源站,CDN 就退化成了一个昂贵的反向代理。
- 节点覆盖与线路质量——节点多不等于好用,线路是否直连、跨网质量如何、调度是否准确,往往比节点数量更能说明问题。
- 回源速度——命中率再高,总有需要回源的时候。源站响应慢、回源链路绕远,都会直接体现在未命中用户的首屏时间上。
- 缓存键与缓存策略的设计——这一项完全掌握在网站自己手里,也是投入产出比最高的优化点。
几个常见的误解
"接了 CDN,网站就一定快"
不一定。动态接口、强个性化的内容、依赖实时计算的页面,本来就不适合长时间缓存;源站数据库查询慢、后端响应动辄几秒,CDN 只能帮你在传输段省下几十毫秒,救不了根本。CDN 优化的是分发,不是计算。
"刷新缓存可以解决所有问题"
刷新只是把已缓存的副本标记为失效,下一次请求依然会回源获取。如果源站内容本身没更新,刷新除了增加回源压力之外并无收益;如果缓存键设计有问题,刷新之后命中率依旧上不去。
"加速就是换个更快的服务器"
CDN 不是替你把服务器搬走,而是在你和用户之间加了一层会记忆、会分流、会走捷径的中间层。理解这一点,才不会把配置问题误判成"服务商不行"。
怎么判断加速是否真的生效
最直接的办法是看响应头。多数 CDN 会在返回中带上诸如 X-Cache、Via、Age 一类的字段,Age 明显大于零通常说明命中了缓存;同一份资源在不同地区多次请求,观察首字节时间和下载耗时的分布,也能看出节点调度是否合理;在控制台里关注命中率曲线和回源带宽占比,则能判断缓存策略是否还有优化空间。把这些数据放在一起看,比凭感觉判断"好像快了一点"要可靠得多。
写在最后
CDN 加速原理拆开来看,无非是三件事:把用户引导到最近的节点,让节点尽可能多地直接给出答案,以及在必须回源时让这段路走得又快又稳。技术上并不神秘,难的是根据自己网站的资源类型、更新频率和用户分布,把缓存键、缓存时间、回源策略这些参数调到合适的位置。理解了这条链路,很多"接了 CDN 还是慢"的困惑,往往能在配置层面找到答案。


