静态资源又大又常被访问,若全打到源站,带宽和延迟都会吃紧。CDN(内容分发网络) 把图片、视频、JS/CSS 等推到各地边缘节点,让用户就近取——像物流把货放到离你最近的仓。
本篇讲清 CDN 与全站加速的差别、回源/预热/刷新的流程、GSLB 如何选节点,以及防盗链机制与为何多数团队直接用云厂商 CDN。
TL;DR
- CDN = 静态资源就近访问:将资源分发到多地机房,加快访问速度、减轻源站与带宽压力。
- ≠ 全站加速:CDN 主攻静态;ECDN/DCDN 等全站加速可同时加速动静态;API 接口不应走 CDN 缓存(个性化/实时数据 + 有副作用的写请求)。
- Cache-Control 决定缓存行为:
max-age + immutable配合内容哈希文件名是静态资源最佳实践,彻底免去手动刷新;HTML 入口应设短 TTL 或no-cache。 - Origin Shield(回源盾):在边缘 POP 与源站之间加一层中间节点,将多节点回源合并为单次,防止大面积过期时的回源风暴。
- 关键指标:命中率(> 90% 为健康)、回源带宽、边缘 TTFB——命中率偏低通常意味着 TTL 太短或 URL 带动态参数。
- 多数团队不自建:从成本、稳定性、易用性综合考量,直接使用云厂商或专业 CDN 厂商更划算。
- 预热提前将资源同步到边缘节点,避免首访回源;回源是节点 miss 或缓存过期时拉取源站内容;刷新是强制清除旧缓存。命中率越高、回源率越低越好。
- GSLB 是 CDN 的调度大脑(常用基于 DNS 实现),综合请求 IP、节点负载等维度选出最优边缘节点。
- 防盗刷手段包括:Referer 防盗链、URL 鉴权、远程鉴权、IP/UA 黑白名单等。
Table of contents
Open Table of contents
1. CDN:静态资源的就近分发
CDN(Content Delivery Network / Content Distribution Network,内容分发网络)的核心思路是:将静态资源分发到部署在多个地理位置的边缘节点,让用户从最近的节点获取资源,而非每次都访问远端源站。
从名称拆解来看:
- 内容:静态资源,包括图片、视频、文档、JS、CSS、HTML 等;
- 分发网络:将这些资源同步到分布全国乃至全球的多个机房,让北京用户从北京节点取,深圳用户从深圳节点取。
这个思路与现代物流体系高度相似:
静态资源像商品,分发到各地「仓」以便就近取。
从架构角度,CDN 可以看作部署在服务上层的特殊缓存层,专门承接静态资源请求,避免这类高频大体积请求对源站造成压力。
CDN 是服务上层的特殊缓存层,专吃静态请求。
CDN ≠ 全站加速。全站加速(腾讯云称 ECDN、阿里云称 DCDN)可以同时加速静态资源和动态接口;而标准 CDN 主要针对静态资源,对动态请求收益有限。
CDN 主攻静态;全站加速可同时加速动静态。
绝大部分公司会在项目中使用 CDN 服务,但极少自建。基于成本、稳定性和运维复杂度考量,建议直接选择云厂商(如阿里云、腾讯云、华为云)或专业 CDN 厂商(如网宿、蓝汛)提供的开箱即用服务。
选择云厂商 CDN 时可参考以下维度:
- 节点覆盖:目标用户在国内还是海外?国内通常首选国内主流云厂商;海外用户多可考虑 Cloudflare、Akamai、CloudFront;
- 计费模式:按流量计费还是按带宽峰值计费,结合自身流量特征选择成本更低的方案;
- 功能需求:是否需要 Origin Shield、边缘函数、DDoS 防护、SSL 证书管理等增强能力;
- 与主云绑定:已重度使用某云厂商时,同厂 CDN 往往集成更便捷(IAM、日志统一、内网回源免费)。
一句话:多地部署服务是为了高可用;CDN 是为了静态资源的就近访问——两件事,不要混为一谈。
同一服务在多地部署多份(同城灾备、异地灾备、多活)解决的是高可用与容灾,与 CDN 的就近访问目标不同,成本也高得多。
CDN 通常也不具备计算能力(Edge Function / Workers 是近年兴起的增强能力,不在本文讨论范围内),它的本质仍是带存储的分发网络,而非分布式计算层。理解这一边界,有助于在架构选型时做出正确取舍:需要计算下沉用边缘函数,需要静态资源加速用 CDN,需要服务高可用用多活部署——三者服务不同目标,通常组合使用。
2. 预热、回源、调度与防盗链
理解 CDN 的工作原理,可以从三个问题入手:
- 静态资源是如何被缓存到 CDN 节点的?
- 如何找到最合适的 CDN 节点?
- 如何防止静态资源被盗用?
2.1 预热、回源与刷新
预热(Prefetch/Warm-up):在用户访问前,主动将源站资源同步到各边缘节点。预热后,用户首次请求即可命中节点缓存,无需回源,降低源站压力并提升首次访问速度。
回源(Origin Pull):若 CDN 节点上没有用户请求的资源,或该资源的缓存已过期,节点将主动向源站拉取最新内容——这个过程称为回源。发生回源时,该请求的响应时间通常比直连源站还慢,因为链路上多了一层 CDN 节点的转发。
刷新(Purge/Refresh):当源站资源更新后,可主动触发刷新,强制清除 CDN 节点上的旧缓存,使下一次请求重新回源获取最新内容。
| 环节 | 触发时机 | 目的 | 典型耗时/影响 |
|---|---|---|---|
| 预热 | 上线前或大促前主动触发 | 避免首次访问回源,降低首访延迟与源站压力 | 视资源总量,通常数分钟到数十分钟完成同步 |
| 回源 | 节点 miss 或缓存已过期 | 从源站拉取最新内容并写入节点缓存 | 该次请求变慢(多一跳);后续请求命中变快 |
| 刷新 | 源站内容更新后手动/API 触发 | 强制清除节点旧缓存,确保下次回源取到最新内容 | 全网生效通常数秒到数十秒,取决于节点规模 |
命中率与回源率是衡量 CDN 服务质量的两个核心指标:命中率越高越好,回源率越低越好。命中率偏低通常意味着缓存策略(TTL 设置、预热时机)需要优化。
部分 CDN 厂商还支持 stale-while-revalidate 语义:缓存过期时,先返回旧内容(避免用户等待),同时异步向源站拉取最新内容更新缓存——对读延迟敏感、允许短暂展示旧版本的场景(如新闻列表、活动横幅)尤为实用。
2.2 GSLB:如何选出最优节点
GSLB(Global Server Load Balance,全局负载均衡)是 CDN 的调度大脑,负责在所有边缘节点之间协调,将请求引导到最优节点。最常用的实现方式是基于 DNS 的 GSLB。
请求调度流程如下:
- 浏览器向 DNS 服务器发送域名解析请求;
- DNS 服务器根据 CNAME 记录将请求转发给 CDN 专属 DNS(GSLB);
- GSLB 综合请求来源 IP、各边缘节点负载、响应时间、带宽等指标,选出最优节点,将其地址返回给浏览器;
- 浏览器直接向该边缘节点发起资源请求。
DNS/GSLB 指路到边缘节点;miss 则回源再缓存。
实际实现中,GSLB 内部通常是 CDN 专属 DNS 与负载均衡系统的组合:DNS 返回负载均衡系统的 IP,浏览器再通过负载均衡系统定位到具体的边缘节点。
2.3 防盗链与访问控制
CDN 分发的内容默认为公开资源,任何人拿到 URL 均可访问。若资源被大量盗刷,将产生不必要的带宽费用。常见的访问控制手段包括:
- Referer 防盗链:校验请求的
Referer头,仅允许来自指定域名的请求; - URL 鉴权(时间戳防盗链):在资源 URL 中附加时间戳和签名,超时或签名错误则拒绝访问;超时时间通常设为 10 分钟至 1 小时;
- 远程鉴权:CDN 节点将鉴权请求转发给业务方自定义的鉴权接口,灵活性最高,适合付费内容、私有文件下载等场景;
- IP 黑/白名单:仅允许或拒绝指定 IP 段的访问;
- UA 黑/白名单:通过 User-Agent 过滤特定客户端或爬虫。
大多数场景下,URL 时间戳鉴权 是性价比最高的防盗链方案:对 CDN 节点透明、无需回源鉴权、且签名难以伪造。Referer 防盗链可以与其叠加,但 Referer 头容易被伪造,不应作为唯一防线。
3. 缓存策略与 HTTP 头
3.1 Cache-Control 与 TTL
浏览器缓存行为由 Cache-Control / Expires 响应头控制,CDN 节点同样遵守这些头信息——但各厂商的 CDN 可能在平台配置页额外叠加或覆盖源站 TTL。
| 响应头配置 | CDN 行为 | 浏览器行为 | 适用场景 |
|---|---|---|---|
Cache-Control: max-age=31536000, immutable | 缓存 1 年 | 1 年内不重新验证 | 内容哈希文件名(app.3f8a2b.js) |
Cache-Control: max-age=300 | 缓存 5 分钟 | 5 分钟后重新验证 | 频繁更新的半静态资源 |
Cache-Control: no-store | 不缓存 | 不缓存 | 敏感接口、实时数据 |
Cache-Control: no-cache | 缓存但每次须向源站验证(ETag) | 同左 | 需强一致但希望节省带宽 |
哈希文件名 + 长 TTL 是静态资源的最佳实践:Webpack/Vite 等构建工具默认为打包产物生成内容哈希后缀(如 main.a1b2c3.js)。文件内容不变则 URL 不变,CDN 可安全缓存 1 年;内容更新则 URL 变化,旧缓存自然淘汰,无需手动刷新。
以一次真实响应为例,静态资源与 HTML 入口的响应头配置应明显不同:
# 静态资源:内容哈希文件名,一年内不重新验证
GET /assets/app.3f8a2b.js HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/javascript
Cache-Control: public, max-age=31536000, immutable
ETag: "3f8a2b1a2b3c"
# HTML 入口:内容会变,必须每次向源站验证
GET /index.html HTTP/1.1
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Cache-Control: no-cache
ETag: "e1a2b39f8e7d"
广告创意、商品图、视频封面等媒体素材同理——只要 URL 带内容哈希(或素材一经发布不再原地覆盖),就可放心设长 TTL 让 CDN 尽量吃满命中:
# 广告创意素材:图片/视频封面,内容哈希 URL,长 TTL 吃满命中率
GET /creatives/banner.9f3c1a.jpg HTTP/1.1
HTTP/1.1 200 OK
Content-Type: image/jpeg
Cache-Control: public, max-age=2592000, immutable # 30 天
Access-Control-Allow-Origin: * # 跨域展位需要
Vary: Accept # 按 WebP/AVIF 协商时才加
no-cache 不等于不缓存——它表示缓存但每次必须带 If-None-Match 向源站验证,验证通过(304)时无需回传响应体,兼顾新鲜度与带宽;若要求完全不缓存(如敏感接口、计费像素),应使用 no-store。
3.2 源站侧的缓存头配置(Nginx)
CDN 的缓存行为最终由源站响应头驱动。以 Nginx 作为素材源站为例,应按路径下发差异化的 Cache-Control:
# 素材源站:按目录区分「可长缓存」与「绝不缓存」
server {
listen 80;
server_name origin.example-cdn.com;
root /data/assets;
# 带内容哈希的创意素材 → 允许 CDN 与浏览器长期缓存
location ~* ^/creatives/.+\.(?:jpg|jpeg|png|webp|avif|mp4|js|css)$ {
add_header Cache-Control "public, max-age=2592000, immutable";
add_header Access-Control-Allow-Origin "*";
access_log off;
}
# VAST 文档:可能含竞价宏/追踪 URL,短 TTL 且必须回源校验
location ~* ^/vast/.+\.xml$ {
add_header Cache-Control "public, max-age=60";
}
# 计费/曝光像素:绝不缓存,每次都要真实打到 Collector
location ~* ^/px/ {
add_header Cache-Control "no-store, no-cache, must-revalidate, max-age=0";
add_header Pragma "no-cache";
expires -1;
}
}
源站头与 CDN 平台配置双重生效:多数云厂商 CDN 支持在控制台按路径覆盖或叠加 TTL。团队约定应以「源站头为准、平台配置只做兜底」,避免两侧各配一套导致缓存行为难以预期。更多 Nginx 配置见 Nginx 配置实践。
3.3 动态内容为何不宜缓存
API 接口通常返回个性化或实时数据(购物车、订单状态、实时价格),这类内容:
- 每次返回结果不同,缓存后下一个用户可能拿到错误数据;
- 携带身份信息(Cookie / Authorization),CDN 节点难以安全地区分不同用户的请求 key;
- 副作用请求(POST / DELETE),不应被缓存。
对于 API,正确做法是在 CDN 配置中将动态路径(如 /api/*)绕过缓存直接回源,或使用全站加速(DCDN/ECDN)的动态加速通道(TCP 复用、BGP 最优路由),而非尝试在 CDN 层缓存 API 响应。
3.4 Origin Shield(回源盾)
大规模 CDN 部署中,当缓存集中失效或突发流量到来时,来自全国各地多个 POP 节点的回源请求会同时打向源站,产生回源风暴。
Origin Shield(回源盾 / 中间层缓存节点) 是解法:在各边缘 POP 节点与源站之间增加一层集中式中间节点。所有 POP 的回源请求先汇聚到中间节点,中间节点再以单一请求向源站拉取,将 N 次回源合并为 1 次,大幅降低源站压力——相关内容也可与 缓存机制 中的缓存雪崩对比理解。
4. 关键指标
| 指标 | 含义 | 健康参考 |
|---|---|---|
| 命中率(Hit Ratio) | 边缘节点直接返回的请求比例 | > 90%(图片/JS/CSS 类资源) |
| 回源带宽 | CDN 向源站拉取内容消耗的带宽 | 越低越好;命中率低时回源带宽高 |
| TTFB(首字节时间) | 客户端到收到第一个响应字节的时间 | 命中时 < 50ms;回源时 200–500ms+ |
| 边缘节点 QPS | 所有 POP 节点合计请求量 | 用于容量规划与费用预估 |
命中率偏低的常见原因:
- TTL 太短:资源频繁过期,每次都需回源;
- URL 带动态参数:资源 URL 含时间戳
?v=1234567或?_=<random>,导致每个请求都是「新 key」,无法复用缓存; - 预热不足:新上线版本没有预热,用户访问全量回源。
监控建议:在云厂商 CDN 控制台配置命中率与回源带宽的告警阈值(如命中率跌破 85% 触发告警),能在用户感知之前发现缓存策略问题。大多数 CDN 厂商的控制台也支持按域名、路径、地区维度下钻分析,便于定位具体是哪类资源命中率低。
5. 常见故障模式
5.1 集中过期引发回源风暴
当大量缓存同时到期(如 CDN 节点重启、TTL 统一设置导致集中失效),所有边缘节点同时向源站发起回源,在极短时间内产生数倍于平时的源站流量。
应对:
- 为不同资源路径设置差异化 TTL,避免整批同时过期;
- 启用 Origin Shield,将多节点回源合并为单节点回源;
- 源站做好自保:限流熔断,超出容量时返回降级内容(如旧版本静态页),参见 负载均衡 中的健康检查与排水机制。
5.2 刷新后缓存未及时失效
手动触发缓存刷新(Purge)后,理论上边缘节点应立即删除旧内容。但在以下情况下可能出现「刷新了但用户仍看到旧版本」:
- CDN 节点数量多,刷新操作异步扩散,存在数秒到数十秒的传播延迟;
- CDN 厂商 API 出现偶发故障,刷新请求未被正确执行;
- 浏览器本地缓存尚未失效(
max-age未到期),CDN 侧刷新对已有浏览器缓存无效。
应对:
- 静态资源使用内容哈希文件名,彻底绕开刷新问题(文件内容变则 URL 变,自动缓存失效);
- 上线流程将「CDN 刷新」纳入发布检查清单,刷新后等待 30–60 秒再验证;
- 对时效性极强的内容(如活动首页)设置较短 TTL(如 60s),缩短刷新失效的影响窗口。
6. 生产清单与反模式
6.1 启用 CDN 的实践清单
| 资源类型 | 建议策略 | 说明 |
|---|---|---|
| JS / CSS(内容哈希文件名) | TTL 365 天 + immutable | 构建工具自动生成哈希名,更新即换 URL |
| 图片 / 字体 | TTL 7–30 天 | 变更频率低,较长 TTL 可有效提升命中率 |
| HTML(入口文件) | TTL 0–5 分钟 或 no-cache | HTML 引用带哈希的资源,本身需保持新鲜 |
API 接口(/api/*) | 不缓存 / 绕过 CDN | 动态数据不应被缓存(§3.3) |
| 大体积下载文件 | TTL 7 天 + 分片传输支持 | 减少重复回源;Content-Disposition 保证正确下载行为 |
上线前 checklist:
- 资源 URL 含内容哈希,或为图片/字体设置显式 TTL;
- HTML 入口的
Cache-Control已设置为短 TTL 或no-cache; - API 路径已在 CDN 配置中设为「不缓存」或「直接回源」;
- 已在测试环境验证 CDN 命中(响应头
X-Cache: HIT); - 大流量活动前已提前完成资源预热;
- 监控已涵盖命中率、回源带宽、源站错误率;
- HTTPS 证书已在 CDN 完成配置(TLS 卸载在边缘节点,后端可用 HTTP 回源降低内网开销);
- 已确认 CDN 节点与源站之间的回源鉴权方式(如 IP 白名单或回源 Token),防止直接绕过 CDN 访问源站;
- 广告场景已确认:创意素材走缓存、计费/曝光像素
no-store且绕过缓存,两类域名/路径物理分离。
6.2 反模式(Anti-patterns)
以下都是生产中真实踩过、且代价不小的坑,逐条对照排查:
| 反模式 | 后果 | 正确做法 |
|---|---|---|
| 回源无收敛:不开 Origin Shield,各 POP 各自回源 | 缓存集中失效/大 campaign 冷启动时回源风暴打垮源站 | 开 Origin Shield 合并回源 + 差异化 TTL + 源站限流(§3.4、§5.1) |
ignore query string 一刀切开全站 | 动态/计费路径被错误归一化,唯一像素被当同一 key 缓存 | 仅对纯静态资源开启;tracking/API 路径显式关闭 |
| URL 带随机参数当缓存 key | 每次都是新 key,命中率≈0,形同没上 CDN | 内容哈希文件名;多尺寸/多格式用不同 URL 而非查询参数 |
| Referer 防盗链当唯一防线 | Referer 易伪造,防不住盗刷与盗用创意 | 签名 URL(时间戳鉴权)为主,Referer 叠加为辅(§2.3) |
| HTML 入口配长 TTL | 发版后用户长时间看到旧页面、加载到已删除的旧资源 | HTML no-cache/短 TTL,静态资源哈希命名配长 TTL |
| 源站不自保 | 回源一旦被打满,正常素材也被拖垮(雪崩) | 回源限流/排队/降级兜底,参见 负载均衡 |
小结
- CDN 的本质是将静态资源分发到多地边缘节点,通过就近访问加快响应、减轻源站与带宽压力。
- 选型建议:基于成本、稳定性和运维复杂度,多数团队直接使用云厂商或专业 CDN 厂商的托管服务,而非自建。
- GSLB 是 CDN 的调度核心,通过基于 DNS 的全局负载均衡机制,综合多维度指标为每次请求选出最优边缘节点。
- 缓存策略:静态资源用内容哈希文件名 + 长 TTL(
max-age + immutable),HTML 入口用短 TTL 或no-cache,API 接口绕过缓存直接回源。 - 提高命中率的关键:合理设置 TTL、避免 URL 带动态参数、在高流量事件前预热、资源更新后及时刷新,避免大量回源冲击源站。
- 防止回源风暴:启用 Origin Shield 将多节点回源合并为单次;结合 负载均衡 中的健康检查确保源站本身高可用。
- 防盗刷配合 Referer 防盗链与 URL 时间戳鉴权,可覆盖大多数场景;高安全性需求可使用远程鉴权。
- CDN 与缓存协同:CDN 是 缓存机制 的链路级应用,本质是服务上层的分布式缓存层,命中率与 TTL 设计的原则高度一致。