CDN 与反向代理:内容分发的网络基础

上一篇 DNS 结尾我们留了个引子:CDN 靠 DNS 把用户导向最近的节点。这一篇就把这条链路走完——当你的网站用户遍布全国甚至全球,仅靠机房里那一台(或一组)源站直接响应所有请求,跨地域延迟、热点资源重复传输、突发流量打爆单点,每一样都够呛。CDN 和反向代理,就是现代 Web 为解决这些问题而长出的两层基础设施。

很多人能说出这两个词,却分不清它们各自解决什么、在链路的哪个位置、怎么配合。一遇到"CDN 回源 502"“Nginx 代理超时”,就把整条链路搅成一团乱麻。

所以这一篇先机制后设计:先看清一个请求打进来后,CDN 怎么判断命中、未命中怎么回源,反向代理又怎么把请求转发到后端这套流程,再回头说为什么要分这两层。 把"用户 → CDN → 反向代理 → 后端"这条链路在脑子里拉直,一切就清楚了。

一、问题的起点:为什么源站扛不住一切

先想清楚不用 CDN 会怎样。所有用户都直连源站,会撞上几个硬伤:

  • 跨地域延迟:用户在广州、源站在北京,每个请求都要跨越大半个中国,RTT 高。回忆前面学的——RTT 高,TCP 慢开始爬升慢、TLS 握手也慢,首屏体验直接受拖累。
  • 重复传输浪费带宽:同一张图片、同一个 JS 文件,被全国用户反复从源站拉取,源站出口带宽被海量重复内容占满。
  • 单点压力与抖动:突发流量(活动、热点)容易把单点压垮;源站或中间链路一抖动,所有用户立刻受影响。

尤其是图片、视频、CSS、JS 这类静态内容——它们内容固定、可被复用,却每次都从一个遥远的点发出,既慢又费。内容分发的需求就此产生。

二、CDN 的核心机制:边缘缓存 + 回源

CDN(内容分发网络)的核心思想一句话:把内容提前放到离用户尽量近的边缘节点上。 CDN 厂商在全国/全球各地部署了大量边缘节点(edge),每个节点都有缓存。

一个请求到达 CDN 边缘节点后的处理逻辑:

  1. 查边缘缓存:边缘节点先看自己缓存里有没有这个资源、且未过期。
  2. 命中(cache hit):直接从这个就近节点返回给用户。又快又省,请求根本不碰源站。
  3. 未命中(cache miss):边缘节点向源站回源(origin pull)——去源站把资源拉回来,一边返回给用户,一边按缓存规则存一份在本地,供后续同样的请求命中。
sequenceDiagram participant U as 用户 participant Edge as CDN边缘节点 participant Origin as 源站(反向代理→后端) U->>Edge: 请求 /static/app.js alt 边缘缓存命中 Edge-->>U: 直接返回缓存内容(快,不回源) else 缓存未命中 Edge->>Origin: 回源拉取 /static/app.js Origin-->>Edge: 返回资源 + 缓存头 Edge->>Edge: 按规则缓存一份 Edge-->>U: 返回内容 end

这张图的关键是那个 alt 分支:命中就近返回、未命中才回源。CDN 的全部收益,都建立在"尽可能多地命中、尽可能少地回源"之上。所以缓存命中率,是衡量 CDN 价值的第一指标(第五节细说)。

那用户的请求是怎么被导到"最近的"边缘节点的?靠上一篇的 DNS:你把域名 CNAME 指向 CDN,CDN 的智能 DNS 解析会根据用户的地理位置/运营商,返回离他最近、最健康的边缘节点 IP。这就是 DNS 和 CDN 在链路最前端的衔接。

三、反向代理的核心机制:统一入口 + 转发

反向代理位于服务端入口,对外它就表现为"服务本身"(用户以为在跟它对话),对内它把请求转发给真正干活的后端应用。Nginx 是最典型的反向代理。

它在一个请求上能做的事:

  • 负载均衡:把请求按策略(轮询、最少连接、一致性哈希等)分发到后端多台实例,是后端横向扩展的基础。
  • TLS 终止:在反向代理这一层解密 HTTPS(上一篇的 TLS 握手在这里完成),之后到后端走明文 HTTP,省去每台后端都配证书、做加密的开销。
  • 请求路由:按域名、路径把请求分发到不同的后端服务(/api 去 A 服务、/img 去 B 服务)。
  • 访问控制、限流、缓存、日志、压缩等横切能力,统一在入口处理。

注意和正向代理区分:正向代理代表客户端去访问外部(如公司出口代理、翻墙代理),服务器不知道真实客户端;反向代理代表一组服务器对外接客,客户端不知道背后有几台后端。一个藏客户端,一个藏服务端,方向相反。

四、把链路拉直:CDN 和反向代理怎么串起来

两者不是二选一,而是串在一条链路上分工协作。一个完整请求的旅程:

  1. 用户请求 → DNS 解析把域名导向 CDN 边缘节点
  2. CDN 边缘命中:直接返回,链路到此结束(静态资源的理想情况);
  3. CDN 边缘未命中:回源——而回源的目标,往往就是源站的反向代理(而非后端本身);
  4. 反向代理收到回源请求,做 TLS 终止、按路径/负载策略转发给后端应用
  5. 后端处理、返回,反向代理回给 CDN,CDN 缓存并返回用户。

链路是 用户 → CDN边缘 →(未命中才)反向代理 → 后端。CDN 管"内容就近分发、削减回源",反向代理管"入口统一治理、转发到后端"。理解这条链路的分段,排障时才不会把"CDN 回源 502"和"Nginx 转后端超时"混成一锅——前者出在 CDN→源站这段,后者出在反向代理→后端这段。

五、缓存命中率:CDN 收益的命脉

CDN 的价值几乎全系于缓存命中率。命中率高,绝大多数请求在边缘就近完成,源站清闲、用户飞快;命中率低,请求频繁回源,CDN 几乎退化成一个多绕一跳的中转,优势尽失。影响命中率的关键因素:

  • 资源是否可缓存:静态资源(图片、JS、CSS)天然可缓存;动态接口(每次结果不同)默认不缓存。
  • 缓存头设置Cache-ControlExpiresETag(上一篇 HTTP 头)直接决定边缘缓存多久、如何校验。配错(比如源站返回 Cache-Control: no-cache)会让 CDN 形同虚设。
  • URL 设计与版本化:带随机查询参数的 URL 会被当成不同资源、各存一份,拉低命中率。而版本化 URL(如 app.v2.jsapp.[hash].js)是更新静态资源的最佳实践——内容变了 URL 就变,既保证用户拿到新版本,又能给旧 URL 设超长缓存。
  • 回源策略:多级缓存(边缘 → 区域中心 → 源站)能进一步减少直接回源。

很多"静态资源优化"的本质,就是在提高命中率、降低回源成本。把可缓存的资源配好长缓存 + 版本化 URL,命中率能从勉强可用拉到接近满命中。这是前端性能优化里性价比最高的一项。

六、看懂机制后,再问:为什么要分这两层

为什么不让源站直接服务,非要 CDN? 因为物理距离和重复传输是绕不开的成本。CDN 把"离用户近"和"减少重复回源"两件事一次解决——它本质是用空间换时间(在各地铺缓存)和缓存换带宽(命中就不占源站带宽)。

为什么要反向代理这一层,后端不能直接对外吗? 可以,但会很糟。直接对外意味着每台后端都要自己处理 TLS、负载均衡无处落地、入口安全和限流分散在各处、后端实例的 IP 直接暴露。反向代理把这些横切关注点收敛到一个统一入口,后端只需专注业务逻辑。这是典型的"关注点分离"——入口治理与业务处理解耦。

为什么 CDN 和反向代理要配合而非互相替代? 它们解决的是链路不同段的问题:CDN 优化"用户到边缘"这段长距离、高重复的传输;反向代理优化"源站入口到后端"这段的治理与分发。一个对外削减距离和回源,一个对内统一接客和转发,职责正交,自然要串起来用。

七、和工程实践 / SRE 的联系

  • 分清是哪一段出问题CDN 回源 502/504 多半是源站(反向代理或后端)挂了或回源超时;Nginx 502 是反向代理连不上/收到后端坏响应;边缘返回 403 可能是 CDN 的访问控制或防盗链规则。先定位链路段,再深挖。
  • 真实 IP 丢失:经过 CDN 和反向代理多层转发后,后端看到的源 IP 是代理的 IP,不是用户的。要靠 X-Forwarded-ForX-Real-IP 头传递真实 IP——配置漏了会导致后端的限流、风控、日志全部基于错误 IP。
  • 缓存错乱:缓存键设计不当(比如把带用户身份的响应缓存了、或忽略了某个区分维度的请求头),会导致 A 用户看到 B 用户的内容。这是 CDN/代理缓存最危险的故障。
  • TLS 配置不一致:边缘、反向代理、回源链路各处的 TLS 版本/证书若不一致,会出现"用户侧 HTTPS 正常,回源握手失败"——和上一篇 HTTPS 排障呼应。
  • 缓存预热与刷新:大型发布前预热(提前把资源推到边缘),发布后按需刷新(purge)旧缓存,避免大量用户同时回源造成的回源风暴。

八、学习这一部分最容易踩的坑

1. 把 CDN 当成"万能加速器"

CDN 主要加速可缓存的静态内容。动态接口、个性化内容默认不命中缓存,接上 CDN 也快不了多少,还可能因配置不当出问题。不是"接上就一劳永逸"。

2. 把反向代理只当成"简单转发"

转发只是它最基础的功能。负载均衡、TLS 终止、限流、安全、可观测性才是它的核心价值。轻视它,就用不好这层入口治理。

3. 把 CDN 和反向代理混为一谈或对立起来

它们在链路不同段、解决不同问题,是配合关系。分不清,排障时就会把"CDN→源站"和"代理→后端"两段问题搅在一起。

4. 忽视缓存命中率和真实 IP

不关注命中率,CDN 可能在大量回源、毫无收益;不处理 X-Forwarded-For,后端的限流风控会全部失准。这两个是落地时最容易被忽略却影响巨大的点。

总结

这一篇我们把内容分发的链路拉直,坚持先机制后设计:

  • 源站直连有跨地域延迟、重复传输、单点压力三大硬伤,催生了内容分发需求;
  • CDN 的机制是边缘缓存 + 回源:命中就近返回,未命中才回源并缓存,靠 DNS 把用户导向最近节点;
  • 反向代理位于服务端入口,统一承担负载均衡、TLS 终止、路由、限流等横切职责;
  • 完整链路是"用户 → CDN边缘 →(未命中才)反向代理 → 后端",两者在不同段分工协作;
  • 缓存命中率是 CDN 的命脉,由可缓存性、缓存头、URL 版本化、回源策略共同决定;
  • 设计上,CDN 用空间换时间削减距离与回源,反向代理把入口治理与业务处理解耦,职责正交。

至此,计算机网络这一系列从 TCP 的可靠传输、拥塞与流量控制,到 HTTP 的演进、报文与 HTTPS,再到 DNS 解析与 CDN 分发,就连成了一条完整的链路——你已经能说清,从输入域名那一刻起,一个请求是怎么被解析、加密、传输、分发、最终送达后端的。

参考资源