CDN(Content Delivery Network,内容分发网络)是现代互联网基础设施的重要组成部分。无论是访问网站、观看视频、下载文件,还是调用 API,都可能涉及 CDN。
对于后端开发和运维工程师来说,理解 CDN 不仅要知道它能加速访问,还要理解它的节点调度、缓存机制、回源流程、DNS 解析、HTTPS、缓存一致性以及安全防护机制。
本文从原理出发,结合实际请求流程和 Nginx 配置,逐步讲解 CDN 的工作方式。
一、CDN 是什么?
1.1 CDN 的核心概念
传统的网站部署方式通常是将应用和静态资源部署在一台或几台源站服务器上。无论用户位于哪里,访问请求最终都需要到达源站,或者经过源站前面的负载均衡系统。
假设源站部署在上海:

这种方式存在几个问题:
-
网络延迟较高:用户与源站距离远,网络传输时间可能较长。
-
源站压力大:所有用户的静态资源请求都可能集中到源站。
-
带宽成本高:图片、视频、安装包等大文件持续占用源站出口带宽。
-
可用性风险集中:源站发生故障时,依赖它的资源可能无法访问。
CDN 的核心思想是:
把内容缓存到分布在不同地域的边缘节点,让用户尽可能从距离自己较近的节点获取内容,而不是每次都访问源站。

注意:图中的节点仅用于说明原理。实际 CDN 节点的分布、缓存内容和调度策略由 CDN 服务商决定,并不是每个节点都预先存有全部资源。
1.2 CDN 中的几个核心角色
| 角色 | 作用 |
|---|---|
| 用户(Client) | 发起 HTTP/HTTPS 请求 |
| DNS / 调度系统 | 将用户引导到合适的 CDN 节点 |
| 边缘节点(Edge Node) | 距离用户较近,负责缓存和响应内容 |
| 上层缓存节点 | 部分 CDN 架构中用于汇聚回源请求、减少源站压力 |
| 源站(Origin) | 保存原始资源或执行动态业务逻辑 |
| CDN 控制平台 | 配置域名、缓存规则、证书、回源策略和安全规则 |
理解这几个角色,就能理解大部分 CDN 工作流程。
二、CDN 的整体工作原理
CDN 的工作可以拆分为两个相互配合的过程:
-
请求调度:决定用户应该连接哪个 CDN 节点。
-
内容分发:决定节点是直接返回缓存,还是向上游获取内容。
这两个过程解决的是不同问题:调度负责选择节点,缓存负责提供内容。
2.1 第一步:DNS 调度------用户如何找到 CDN 节点?
假设你的网站域名是:
www.example.com
接入 CDN 后,服务商可能会要求将该域名配置为 CNAME,指向 CDN 分配的域名,例如:
www.example.com
CNAME
cdn.example-cdn.net
上面是示意域名,不代表真实服务商配置。
用户访问网站时,解析过程可以简化为:

这里有一个重要概念:DNS 调度不等于 HTTP 请求转发。
DNS 主要告诉客户端应该连接哪个 IP 地址。得到 IP 后,浏览器通常会直接与该 IP 建立连接,再发送 HTTP 请求。
DNS 调度系统可能综合考虑:
-
地域:用户使用的 DNS 解析器位于哪里。
-
运营商和网络线路:例如电信、联通、移动等网络。
-
节点健康状态:避免将流量调度到故障节点。
-
网络性能:延迟、丢包、带宽等指标。
-
负载情况:部分服务商会结合节点负载进行调度。
需要注意,传统 DNS 调度通常只能近似判断用户的位置,因为它经常看到的是递归 DNS 服务器的位置,而非用户设备的真实位置。EDNS Client Subnet 等机制可以在支持时改善这一点。
此外,DNS 结果存在缓存。即使 CDN 已经调整调度策略,客户端或递归 DNS 仍可能在一段时间内使用旧的解析结果。
2.2 第二步:边缘节点如何处理 HTTP 请求?
当浏览器获得 CDN 节点 IP 后,会向该节点发送请求。
例如:
GET /images/logo.png HTTP/1.1
Host: www.example.com
Accept: image/avif,image/webp,image/*
CDN 节点通常需要根据请求判断:
-
请求的域名是否已经接入 CDN。
-
请求路径对应什么资源。
-
这个请求是否允许缓存。
-
节点上是否有可用的缓存副本。
-
如果没有缓存,应该向哪个上游节点或源站获取资源。
其中最关键的就是缓存命中与未命中。
2.3 第三步:缓存命中(Cache Hit)
假设用户请求:
https://www.example.com/images/logo.png
而 CDN 节点已经缓存了这个文件,且缓存仍然有效。
处理流程如下:

这个过程中通常不需要访问源站。
收益主要有三个:
-
减少用户到内容服务器之间的网络距离。
-
减少源站请求量和出口带宽消耗。
-
降低源站负载,提高静态资源交付效率。
但要注意:缓存命中也不意味着一定很快。如果用户到 CDN 节点的网络质量较差,或者节点本身拥塞,仍然可能出现高延迟。
2.4 第四步:缓存未命中(Cache Miss)
假设某个 CDN 节点第一次收到 logo.png 请求,本地还没有缓存该文件。
这时节点需要向上游获取资源:

实际流程有两点值得注意。
第一,MISS 不一定直接访问源站。 部分 CDN 采用多级缓存架构,边缘节点可能先查询父节点或区域缓存节点。
第二,MISS 不一定会形成缓存。 如果响应带有禁止缓存的指令、资源不满足缓存规则,或者请求属于不适合缓存的动态业务,即使成功从源站获取资源,也可能不保存副本。
2.5 第五步:为什么第一次访问慢,第二次访问快?
假设源站位于上海,用户在成都,CDN 在成都有一个可用节点。
| 请求情况 | 处理方式 | 性能表现 |
|---|---|---|
| 第一次访问 | 成都节点未命中,需要回源 | 可能较慢 |
| 第二次访问 | 成都节点直接返回缓存 | 通常更快 |
| 缓存过期 | 节点可能重新验证或重新获取 | 可能再次变慢 |
| 资源更新后 | 取决于缓存失效、版本号和刷新策略 | 可能出现新旧内容差异 |
这里的"第一次慢、第二次快"只是典型情况,不是必然规律。不同用户可能命中不同节点,不同 URL 也可能拥有完全独立的缓存状态。
三、CDN 缓存机制详解
缓存是 CDN 最核心的技术之一。理解缓存,需要先弄清楚:缓存的是什么、缓存多久、什么情况下重新获取,以及如何让用户看到新版本。
3.1 CDN 缓存的是什么?
CDN 通常缓存 HTTP 响应中的资源内容,例如:
-
图片:JPG、PNG、WebP、AVIF。
-
前端文件:JS、CSS、字体文件。
-
下载文件:APK、安装包、固件、压缩包。
-
视频:切片文件、点播媒体内容。
-
部分可缓存的 API 响应。
一般来说,CDN 并不是在缓存整台源站服务器,也不是把数据库复制到边缘节点,而是根据缓存规则保存特定 HTTP 响应的副本。
一个 HTTP 缓存对象通常涉及:
-
请求方法。
-
请求的 Host 和 URL 路径。
-
查询参数。
-
部分影响响应内容的请求头。
-
响应正文及相关响应头。
-
缓存有效期、验证器等元数据。
实际缓存键(Cache Key)由 CDN 的实现和配置决定,不一定包含上述所有字段。
3.2 什么是 Cache Key(缓存键)?
缓存键决定了不同请求是否被视为同一个缓存对象。
假设存在以下两个请求:
https://cdn.example.com/images/a.png?width=100
https://cdn.example.com/images/a.png?width=500
如果源站根据 width 参数返回不同尺寸的图片,那么这两个请求必须在缓存逻辑上区分开。
一种设计是:
Cache Key = Host + Path + width 参数
于是两个请求对应不同缓存对象。
如果 CDN 配置忽略了 width 参数,就可能把宽度为 100 的图片错误地返回给要求宽度为 500 的用户。
反过来,如果某些查询参数不影响响应内容,却全部加入缓存键,也会造成缓存碎片化,降低缓存命中率。
因此,缓存键必须覆盖所有会影响响应内容的关键请求维度,同时尽量排除无关参数。
3.3 HTTP 缓存控制:Cache-Control
源站可以通过 HTTP 响应头向缓存系统传递缓存策略。
例如:
HTTP/1.1 200 OK
Content-Type: image/png
Cache-Control: public, max-age=3600
这里的 max-age=3600 表示响应在新鲜期内可使用 3600 秒,即一小时。
常见指令如下:
| 指令 | 含义 |
|---|---|
max-age=3600 |
响应的新鲜期为 3600 秒 |
public |
允许共享缓存存储该响应,仍须满足其他缓存条件 |
private |
响应原则上只能由私有缓存存储,不应由共享缓存存储 |
no-cache |
存储并非一概禁止,但使用前通常需要重新验证 |
no-store |
不存储该响应 |
s-maxage=3600 |
为共享缓存指定新鲜期,并优先于 max-age 等相关规则 |
must-revalidate |
响应过期后,在规定条件下必须重新验证,不能随意直接使用过期内容 |
需要特别区分 no-cache 和 no-store:它们不是同一个意思。
-
no-cache:可以保存,但使用前需要验证是否仍然有效。 -
no-store:不应存储该响应。
另外,CDN 平台可能配置独立的缓存 TTL,覆盖或调整源站缓存策略。实际行为取决于 CDN 的配置和实现。
3.4 Cache-Control 的工作流程
假设源站返回:
Cache-Control: public, max-age=600
ETag: "v1-abc123"
CDN 获得响应后,通常会在适用的缓存规则允许时保存资源。
在 600 秒的新鲜期内,如果同一个缓存对象再次被请求,节点通常可以直接使用缓存。
过了 600 秒后,缓存变为陈旧(stale),这并不等于资源必然立即删除。CDN 可能重新向源站请求资源,也可能根据验证策略检查原缓存是否仍然有效。
3.5 ETag 与 Last-Modified:如何验证资源是否变化?
HTTP 提供了两种常见的缓存验证方式。
ETag:实体标签
源站可以返回:
ETag: "v1-abc123"
缓存过期后,CDN 可以发送:
If-None-Match: "v1-abc123"
如果源站确认资源未变化,可以返回:
HTTP/1.1 304 Not Modified
304 响应通常不包含完整资源正文,缓存系统可以继续使用原有内容,并按响应规则更新相关缓存元数据。
Last-Modified:最后修改时间
源站也可以返回:
Last-Modified: Tue, 13 Oct 2026 08:00:00 GMT
之后,缓存系统可以使用:
If-Modified-Since: Tue, 13 Oct 2026 08:00:00 GMT
让源站判断资源是否发生变化。
两者的主要区别:
| 对比项 | ETag | Last-Modified |
|---|---|---|
| 判断依据 | 实体标签 | 修改时间 |
| 精度 | 取决于标签生成方式,可识别更细粒度的变化 | 时间精度通常较粗 |
| 实现方式 | 源站生成标签 | 源站提供修改时间 |
| 典型用途 | 精确验证资源版本 | 基于文件修改时间进行验证 |
ETag 不一定是文件的 MD5 或 SHA 哈希,它也可以由应用按自己的版本策略生成。
3.6 CDN 缓存刷新与预热
这两个功能经常出现在 CDN 管理后台,但用途不同。
缓存刷新(Purge / Invalidation)
让 CDN 已有缓存失效或要求节点重新获取资源。适合网站更新、错误文件修复、敏感内容下线等场景。
注意:不同服务商的刷新语义不同,不一定会立即从所有节点物理删除数据。
缓存预热(Prefetch)
提前让 CDN 获取指定资源,使后续用户访问时更有机会直接命中缓存。
适合大型活动、软件版本发布、视频上线、热门下载文件等场景。
预热并不意味着所有 CDN 节点都一定会保存该资源。节点分布、预热范围、容量限制和服务商策略都会影响结果。
3.7 为什么 CDN 更新后仍然看到旧文件?
这是前端发布中最常见的 CDN 问题之一。
假设前端发布了新版本的 app.js,但是 CDN 仍然返回旧版本,可能有以下原因:
-
CDN 仍在使用旧缓存。
-
浏览器本地缓存仍在使用旧文件。
-
中间代理或其他缓存层没有更新。
-
不同 CDN 节点的缓存状态不同。
-
HTML 已更新,但引用的资源路径没有变化,或者 HTML 本身仍是旧缓存。
推荐的工程方案是文件名版本化或内容哈希。
例如:
旧版本:
/static/app.js
新版本:
/static/app.a81f93c2.js
内容发生变化时,生成新的文件名,浏览器和 CDN 就会将它视为新的 URL。
通常可以采用:
# 带内容哈希的静态资源
Cache-Control: public, max-age=31536000, immutable
# HTML 入口文件
Cache-Control: no-cache
第一种资源名包含内容哈希,适合长时间缓存;HTML 入口则可以在使用前重新验证,减少引用旧资源的风险。
这里的 immutable 是面向客户端缓存的提示,并不代表 CDN 永远不刷新。部署时仍要根据实际缓存规则进行配置。
四、CDN 到底能加速多少?网络原理分析
理解 CDN 的性能收益,需要先了解 HTTP 请求耗时的组成。
4.1 一个请求经历了哪些网络阶段?

在没有连接复用的情况下,TCP 和 TLS 握手可能消耗多个网络往返时间(RTT)。对于跨地域、高延迟网络,这部分开销可能非常明显。
CDN 主要通过以下方式优化:
-
让用户连接地理位置或网络路径更合适的节点。
-
让静态资源从边缘节点直接返回,避免每次都跨地域访问源站。
-
减少源站计算、数据库查询和网络传输压力。
-
通过连接复用、TLS 会话恢复、HTTP/2 或 HTTP/3 等机制改善传输效率,具体取决于平台支持情况。
4.2 CDN 为什么不能解决所有性能问题?
CDN 对静态资源通常很有效,但如果一个请求的主要耗时来自应用计算或数据库查询,CDN 未必能带来明显收益。
例如:
GET /api/order/list
如果这个接口需要:
-
验证用户身份。
-
查询 MySQL。
-
联合查询订单和商品。
-
进行业务计算。
-
返回当前用户的订单数据。
那么响应内容往往是用户相关的动态数据,不应简单地让 CDN 对所有用户共享缓存。
这类接口通常需要从以下方向优化:
-
SQL 查询和索引设计。
-
Redis 等应用缓存。
-
数据库连接池。
-
后端并发处理。
-
应用层和数据库层的性能监控。
当然,经过专门设计的公共 API、可共享的查询结果和动态加速服务也可以从 CDN 获益,但必须先解决缓存隔离和数据正确性问题。
五、CDN 如何区分静态资源与动态请求?
5.1 静态资源缓存
例如:
/static/app.js
/static/app.css
/images/logo.png
/download/firmware-v2.0.zip
这些资源通常具有相对稳定的内容,适合设置缓存策略。
典型响应:
HTTP/1.1 200 OK
Content-Type: application/javascript
Cache-Control: public, max-age=86400
这表示响应可以在满足缓存规则的前提下缓存一天。
但 CDN 不会仅仅因为文件后缀是 .js 就必然缓存。具体是否缓存,还取决于缓存规则、请求方式、响应状态码、源站响应头及平台策略。
5.2 动态请求
例如:
/api/login
/api/order/create
/api/user/profile
/api/payment/callback
这类请求往往需要到源站应用处理。
常见架构是:
客户端
|
v
CDN 边缘节点
|
+---- 静态资源缓存命中 ----> 直接响应
|
+---- 动态请求 ------------> 源站 / 负载均衡 / 应用
有些 CDN 还提供动态内容加速,例如优化链路选择、连接复用和回源连接等。即使不缓存动态响应,也可能减少网络开销。
5.3 Cookie、Authorization 和缓存隔离
假设接口返回用户个人信息:
GET /api/user/profile HTTP/1.1
Authorization: Bearer user-token
如果 CDN 错误地把该响应作为公共缓存,并且不同用户共享同一个缓存键,就可能发生严重的数据泄露。
因此,设计缓存规则时需要重点关注:
-
Authorization是否影响响应。 -
Cookie是否包含会话或用户身份信息。 -
是否存在用户专属数据。
-
Vary响应头是否正确使用。 -
缓存键是否包含所有必要的区分维度。
-
CDN 是否允许缓存带身份认证信息的请求。
一般来说,登录、支付、个人中心、订单查询等接口应默认谨慎处理缓存,除非已经明确设计了安全的缓存隔离方案。
六、HTTPS 接入 CDN 的原理
CDN 接入 HTTPS 时,涉及两段甚至多段通信链路。
6.1 两种常见的 HTTPS 架构
方案 A:客户端 HTTPS,CDN 到源站 HTTP

优点是源站配置相对简单;缺点是 CDN 到源站的链路没有 TLS 加密,不适合不可信网络或敏感数据场景。
方案 B:客户端 HTTPS,CDN 到源站 HTTPS

客户端到 CDN、CDN 到源站分别建立 TLS 连接。需要.
正确配置源站证书、回源协议和证书校验。
方案 B 是对敏感业务更稳妥的常见选择,但也需要根据网络边界和信任模型确定具体配置。
6.2 证书应该配置在哪里?
使用 CDN 后,通常需要关注两类证书:
| 证书位置 | 用途 |
|---|---|
| CDN 边缘证书 | 让浏览器能够通过 HTTPS 安全访问 CDN 域名 |
| 源站证书 | 当 CDN 通过 HTTPS 回源时,供 CDN 校验源站身份 |
两张证书可以不同,也不一定必须使用同一个证书颁发机构。关键是域名匹配、有效期和验证链正确。
6.3 CDN 与 Nginx 反向代理有什么区别?
两者在实现上有相似之处,但定位不同。
| 对比项 | CDN | Nginx 反向代理 |
|---|---|---|
| 部署位置 | 通常由服务商在多地域部署 | 通常由自己部署和维护 |
| 节点分布 | 多地域、跨运营商网络 | 取决于自行部署的服务器 |
| 请求调度 | 可通过 CDN 调度系统完成 | 通常依赖 DNS、负载均衡或上游配置 |
| 缓存 | 通常具备分布式边缘缓存 | 可以配置本地代理缓存 |
| 安全防护 | 可能提供 DDoS、WAF、Bot 防护等服务 | 需要自行配置或组合其他安全产品 |
| 运维成本 | 需要配置 CDN 产品和规则 | 需要维护代理服务器和基础设施 |
需要注意,CDN 不是反向代理的替代品。在很多实际系统中,CDN 和 Nginx 会同时使用。
例如:
用户
|
v
CDN
|
v
Nginx 负载均衡
|
+---- 应用服务器 A
+---- 应用服务器 B
+---- 应用服务器 C
CDN 负责边缘交付和相关安全能力,Nginx 负责源站入口的路由、负载均衡和其他应用接入逻辑。
七、CDN 与 DNS、负载均衡、反向代理的关系
这些技术容易混淆,但实际上解决的问题不同。
| 技术 | 核心问题 | 典型工作方式 |
|---|---|---|
| DNS | 域名应该解析到哪里? | 域名解析与调度 |
| CDN | 内容应该从哪里交付? | 边缘节点缓存、回源 |
| 负载均衡 | 多台后端服务器如何分配请求? | 按策略转发流量 |
| 反向代理 | 如何代理访问后端服务? | 接收请求并转发 |
| Redis 缓存 | 应用如何快速获取热点数据? | 内存键值查询 |
| 数据库复制 | 如何在数据库节点之间复制数据? | 主从复制或其他复制机制 |
一个典型的网站架构可以同时包含所有这些技术:
浏览器
|
| DNS 解析
v
CDN 边缘节点
|
| 未命中缓存或动态请求
v
源站 Nginx / 负载均衡
|
v
Go / PHP / Java 应用
|
+------ Redis
|
+------ MySQL
这种分层架构的价值在于:不同层分别解决网络交付、流量分配、业务计算和数据访问问题。
八、CDN 实战:如何接入一个网站?
假设你已经有一个网站:
www.example.com
源站运行在一台公网服务器上,使用 Nginx 提供网站服务。
接入 CDN 的典型步骤如下。
-
准备源站
确认源站能够正常提供网站内容,并记录源站域名或 IP、回源端口和协议。
-
在 CDN 平台添加加速域名
选择加速业务类型,例如静态资源、网站加速或下载加速,并配置源站地址。
-
配置缓存规则
按文件类型、路径、状态码和业务需求设置缓存 TTL。对登录、支付、用户数据等接口明确禁止不安全的公共缓存。
-
配置 HTTPS
为 CDN 加速域名配置证书。如果采用 HTTPS 回源,还要正确配置源站证书与回源协议。
-
修改 DNS 记录
按服务商提供的接入信息,将加速域名配置为指定的 CNAME。不要直接照搬示例域名或 IP。
-
验证缓存和回源
使用
curl检查 HTTP 状态、响应头、缓存命中情况,并确认源站日志和 CDN 日志符合预期。
8.1 使用 curl 验证 CDN 是否生效
首先检查 DNS 解析:
dig www.example.com
dig CNAME www.example.com
如果 CDN 使用 CNAME 接入,可以查看域名的 CNAME 链;某些 DNS 配置可能直接返回最终地址或采用其他解析方式,因此不能只凭一次查询判断 CDN 是否生效。
再检查 HTTP 响应:
curl -sS -D - -o /dev/null \
https://www.example.com/images/logo.png
这个命令会输出响应头,但不下载完整响应正文到终端。
重点关注以下信息:
HTTP/2 200
Content-Type: image/png
Cache-Control: public, max-age=3600
Age: 120
Via: ...
X-Cache: HIT
以上响应头仅为示例。真实 CDN 不一定提供这些字段,也可能使用其他名称。
| 响应头 | 可以说明什么 |
|---|---|
Age |
共享缓存中该响应的当前驻留时间信息;并非所有 CDN 都会返回 |
Via |
可能显示中间代理信息 |
X-Cache |
部分 CDN 用它表示 HIT、MISS 等缓存状态 |
Cache-Control |
描述响应的缓存策略 |
ETag |
可用于验证资源版本 |
Server |
有时可以辅助识别服务端软件,但不能单凭它确定是否经过 CDN |
连续请求两次:
curl -sS -D - -o /dev/null \
https://www.example.com/images/logo.png
curl -sS -D - -o /dev/null \
https://www.example.com/images/logo.png
如果第一次返回 MISS,第二次返回 HIT,通常说明缓存正在生效。
不过,部分 CDN 可能在响应客户端之前就异步缓存,或使用不同的缓存状态表达方式,所以要结合平台日志判断。
8.2 如何直接测试指定 CDN IP?
在排查 DNS 调度问题时,可以通过 curl --resolve 指定测试 IP:
curl -sS -D - -o /dev/null \
--resolve www.example.com:443:203.0.113.10 \
https://www.example.com/images/logo.png
这里的 203.0.113.10 是文档示例地址,实际操作时应替换为服务商提供的可用 CDN 节点 IP。
这种方式保留 URL 中的域名,因此通常也会使用该域名进行 TLS 证书验证和 HTTP Host 匹配,但会绕过正常的 DNS 地址选择。
如果不同节点返回不同结果,可以进一步排查节点缓存、调度策略、回源链路或源站配置。
九、Nginx 缓存示例:理解 CDN 的底层实现思路
CDN 服务商内部实现比较复杂,但其缓存思想可以通过 Nginx 代理缓存来理解。
下面是一个简化的 Nginx 配置示例。它展示的是源站反向代理缓存,并不是完整的全球 CDN。
http {
proxy_cache_path /var/cache/nginx/cdn_cache
levels=1:2
keys_zone=static_cache:100m
max_size=10g
inactive=60m
use_temp_path=off;
server {
listen 80;
server_name www.example.com;
location /static/ {
proxy_pass http://127.0.0.1:8080;
proxy_cache static_cache;
# 缓存键:协议、域名、请求 URI
proxy_cache_key "$scheme$host$request_uri";
# 正常响应缓存 10 分钟
proxy_cache_valid 200 10m;
# 合并同一缓存键的并发回源请求
proxy_cache_lock on;
# 仅用于诊断缓存状态
add_header X-Proxy-Cache $upstream_cache_status always;
}
}
}
在适用的 Nginx 版本和配置条件下,$upstream_cache_status 可以显示 HIT、MISS、BYPASS、EXPIRED 等状态。
这份配置有几个值得注意的地方:
-
proxy_cache_path:定义缓存文件的磁盘路径、共享内存区和容量相关策略。 -
proxy_cache_key:决定哪些请求共用一个缓存对象。 -
proxy_cache_valid:指定特定状态码的缓存有效期。 -
proxy_cache_lock:减少同一缓存对象未命中时大量并发请求同时回源的问题。 -
X-Proxy-Cache:帮助调试缓存行为。
生产环境注意事项: 该配置只适合在确认资源可安全共享的前提下使用。需要进一步评估源站返回的 Cache-Control、Set-Cookie、Vary 等响应头,以及请求中的身份信息。缓存键中包含 $request_uri,也意味着不同查询参数会产生不同缓存对象。
另外,max_size=10g 是缓存磁盘空间管理参数,不代表 Nginx 会预先占用 10GB 内存。
如果需要实现真正的 CDN,还必须解决多地域节点部署、全球或区域调度、节点健康检测、证书管理、缓存同步或失效、回源保护和大规模流量管理等问题。
十、CDN 的高级机制
10.1 回源风暴与请求合并
假设某个热门文件的缓存刚刚过期,在短时间内有 10,000 个请求到达同一节点。
如果所有请求都各自访问源站,就可能造成回源流量突然增大,这种情况常被称为回源风暴。
典型解决方案包括:
-
请求合并(Request Collapsing):同一个缓存对象只让部分请求发起回源,其余请求等待共享结果。
-
缓存锁(Cache Lock):控制同一缓存键的并发填充。
-
上层缓存:让多个边缘节点共享部分上游缓存。
-
主动预热:在流量到来前获取热门资源。
-
合理的过期和刷新策略:减少大量缓存同时失效的情况。
不同 CDN 对这些机制的支持和实现方式不同。
10.2 缓存穿透与不存在的资源
如果攻击者持续请求大量不存在的 URL:
/random-001.jpg
/random-002.jpg
/random-003.jpg
由于每个请求都是新的缓存键,CDN 可能频繁向源站回源。
可以结合以下措施降低影响:
-
对确定不会变化的 404 响应设置合理的负缓存策略。
-
对异常 URL 和高频请求实施限流。
-
过滤无效参数和不符合业务规范的请求。
-
使用 WAF、Bot 管理或其他适当的安全策略。
-
监控回源 QPS、源站 404 比例和缓存未命中率。
负缓存同样要谨慎:如果源站刚刚创建了一个此前不存在的资源,过长的 404 缓存可能导致用户暂时仍然看不到新资源。
10.3 CDN 与 DDoS 防护
CDN 可以在边缘节点分担部分请求流量,并可能集成 DDoS 缓解、WAF、速率限制和 Bot 防护能力。
但是,接入 CDN 不代表源站天然安全。
如果源站 IP 仍然公开,攻击者可能绕过 CDN 直接访问源站,造成带宽耗尽或应用资源被消耗。
常见的源站保护措施:
-
在源站防火墙中限制 HTTP/HTTPS 入口,仅允许可信 CDN 回源地址访问。
-
如果平台支持,验证回源专用身份信息或使用其他源站认证机制。
-
定期检查 DNS、历史解析记录和其他可能暴露源站 IP 的位置。
-
保留必要的管理入口,但不要无差别地将所有端口开放给 CDN 网段。
-
监控源站流量,发现绕过 CDN 的异常请求及时处理。
需要注意:只允许 CDN IP 访问源站是一项有用的控制,但不能单独代替应用认证、授权和安全配置。
10.4 CDN 缓存一致性问题
CDN 缓存本质上是源站内容的副本,因此源站更新后,副本可能在一段时间内保持旧版本。
可以采用以下策略:
| 业务类型 | 推荐策略 |
|---|---|
| 带内容哈希的 JS/CSS | 长 TTL,资源变化时使用新 URL |
| HTML 入口页 | 短 TTL 或重新验证 |
| 用户头像等普通图片 | 结合更新频率设置 TTL,必要时版本化 |
| 下载文件或固件 | 版本化 URL,发布时预热,必要时刷新 |
| 个人信息和订单数据 | 默认不使用共享公共缓存,除非经过专门设计 |
| 需要快速撤回的内容 | 建立缓存刷新、版本控制和验证流程 |
如果业务对数据时效性要求极高,不应仅依赖 CDN TTL 来保证一致性,而应设计明确的失效、版本管理和数据隔离机制。
十一、CDN 常见故障与排查思路
| 故障现象 | 可能原因 | 排查方向 |
|---|---|---|
| 域名无法访问 | DNS 配置错误、证书或节点问题 | dig、curl -v、检查 CDN 状态 |
| 返回旧的 JS/CSS | CDN 或浏览器缓存未更新 | 检查 URL 版本、缓存规则、刷新记录 |
| CDN 返回 403 | 鉴权规则、Referer 防盗链、WAF 或源站权限问题 | 对照 CDN 访问日志、规则和源站日志 |
| CDN 返回 502/504 | 回源不可达、源站超时、上游异常 | 检查源站健康、回源协议、端口和超时 |
| 缓存命中率低 | URL 参数过多、TTL 太短、缓存键不合理 | 分析请求 URL 分布、缓存状态和规则 |
| 源站流量仍然很高 | 动态请求较多、缓存未命中或源站被绕过 | 检查回源流量、源站访问日志和缓存配置 |
| HTTPS 报错 | 证书过期、域名不匹配、回源 TLS 配置错误 | 分别检查客户端证书与源站证书 |
| 不同用户看到不同内容 | 地域节点差异、缓存键缺失必要维度、Cookie 或参数问题 | 对比不同节点的响应头、缓存键和源站返回 |
建议在排查时把三个问题分开:
-
请求是否到达了正确的 CDN 节点?
-
节点是否返回了正确的缓存内容?
-
如果发生回源,源站是否正确处理了请求?
这样能够避免把所有问题都归因于"CDN 缓存没刷新"。
十二、总结:从工程视角理解 CDN
CDN 并不是简单地把文件复制到几台服务器上,而是一套由调度、边缘缓存、回源、协议优化和安全控制共同组成的分布式内容交付系统。
最值得掌握的知识点有五个:
-
DNS 调度决定客户端连接哪个节点。
-
缓存键与缓存策略决定哪些请求可以共享缓存、缓存多久。
-
回源机制决定未命中时如何获取内容,以及如何避免源站压力骤增。
-
HTTPS 与安全防护决定客户端、CDN 和源站之间的通信是否安全,以及如何限制恶意流量。
-
版本管理与缓存失效决定内容更新后,用户何时能够看到正确的新版本。