CDN 与全球加速
从"为什么我的网站在国外打开这么慢"出发,全面拆解 CDN 的核心原理、缓存策略、回源机制、边缘计算能力——让你从"会用 CDN"到"能调好 CDN",覆盖静态资源分发、动态加速、HTTPS 优化和成本控制。
1. 为什么需要 CDN
你在上海访问自己部署在上海的网站,200ms 加载完成。然后给一个美国朋友看——他等了 3 秒还没打开。同样的服务器、同样的代码、同样的带宽——唯一的区别是距离。这一章解释为什么"距离"会让 Web 体验天差地别,以及 CDN 是怎么解决这个问题的。
1.1 距离的代价:一个 HTTP 请求的旅程
光速不是无限的。
上海 → 洛杉矶,光纤直线距离约 10,500 km
光在光纤中的传播速度 ≈ 光速的 2/3 ≈ 200,000 km/s
单程延迟 = 10,500 / 200,000 = 52.5ms
但网络请求是"请求 + 响应"——一个往返(RTT):
RTT = 52.5ms × 2 = 105ms
这只是"光跑一个来回"的理论最优值。
真实网络还有路由器跳转、排队、拥塞……
实测 RTT 通常是理论值的 1.5-3 倍:
→ 上海 ↔ 洛杉矶实测 RTT ≈ 150-200ms一次 HTTPS 请求需要多少个 RTT?
加载一个 HTTPS 页面需要经历:
1. DNS 解析 1 RTT (问 DNS 服务器这个域名的 IP)
2. TCP 三次握手 1 RTT (SYN → SYN-ACK → ACK)
3. TLS 握手 2 RTT (TLS 1.2) 或 1 RTT (TLS 1.3)
4. HTTP 请求/响应 1 RTT (发请求 → 收到第一个字节)
─────────────────────────
总计 5 RTT (TLS 1.2) 或 4 RTT (TLS 1.3)
上海 → 洛杉矶(RTT ≈ 180ms):
→ 首字节到达 = 180ms × 5 = 900ms(TLS 1.2)
→ 加上页面需要加载 CSS/JS/图片(又要多次请求)
→ 实际体感:2-4 秒
上海 → 上海(RTT ≈ 5ms):
→ 首字节到达 = 5ms × 5 = 25ms
→ 实际体感:200ms
同一个网站,距离不同,体验差 10 倍以上。各地到源站的延迟对比(源站在上海):
| 用户位置 | 与源站距离 | 实测 RTT | 首字节时间(TTFB) | 体感加载 |
|---|---|---|---|---|
| 上海本地 | 0 km | ~5ms | ~25ms | 极快 |
| 北京 | ~1,100 km | ~30ms | ~150ms | 快 |
| 香港 | ~1,500 km | ~40ms | ~200ms | 快 |
| 新加坡 | ~3,800 km | ~70ms | ~350ms | 可以接受 |
| 东京 | ~1,800 km | ~50ms | ~250ms | 可以接受 |
| 洛杉矶 | ~10,500 km | ~180ms | ~900ms | 明显等待 |
| 伦敦 | ~9,200 km | ~250ms | ~1,250ms | 慢 |
| 圣保罗 | ~18,000 km | ~350ms | ~1,750ms | 很慢 |
💡 物理距离是 Web 性能的"隐形杀手"。你可以把服务器 CPU 从 4 核升到 64 核、把数据库查询从 100ms 优化到 1ms——但如果用户在地球另一边,光速限制的 RTT 你完全无法优化。唯一的解决办法是:把内容放到离用户更近的地方。
1.2 CDN 的核心思路:把内容搬到用户身边
既然"距离"是问题根源,解决方案也很直觉:在全球各地放服务器,把内容提前复制过去,让用户从最近的服务器获取。这就是 CDN(Content Delivery Network,内容分发网络)。
没有 CDN 的世界:
═══════════════════════════════════════════
巴西用户 源站(上海)
────── 18,000 km ──────────▶ 🖥️
RTT: 350ms × 5 = 1,750ms
体感:慢得想关掉
有 CDN 的世界:
═══════════════════════════════════════════
巴西用户 圣保罗 CDN 节点 源站(上海)
── 50km ──▶ 📦 有缓存?直接返回!
📦 没缓存?→ 回源站拿,缓存后给用户
RTT: 5ms × 5 = 25ms(命中缓存时)
体感:和访问本地网站一样快CDN 的工作流程(简化版):
用户访问 https://static.example.com/logo.png
Step 1: DNS 解析
════════════════
static.example.com → CNAME → cdn.provider.com
→ CDN 的智能 DNS 返回离用户最近的边缘节点 IP
Step 2: 请求到达边缘节点
════════════════
用户 → 最近的 CDN 节点(比如圣保罗节点)
Step 3: 缓存命中?
════════════════
缓存命中(HIT)→ 直接返回文件,完成!✅
缓存未命中(MISS)→ 进入 Step 4
Step 4: 回源
════════════════
CDN 节点 → 源站(上海):请求 /logo.png
源站返回文件
CDN 节点缓存一份,然后返回给用户
→ 下一个巴西用户再请求这个文件时就是 HIT 了CDN 能加速什么?
| 内容类型 | CDN 效果 | 原因 |
|---|---|---|
| 图片/视频/字体 | ⭐⭐⭐⭐⭐ 极佳 | 完全静态、缓存命中率极高 |
| CSS / JS 文件 | ⭐⭐⭐⭐⭐ 极佳 | 静态文件、哈希命名后可永久缓存 |
| HTML 页面 | ⭐⭐⭐ 较好 | 可缓存但 TTL 较短(内容可能变化) |
| API 接口 | ⭐⭐ 一般 | 动态内容不能缓存内容本身,但可以优化传输路径 |
| WebSocket | ⭐ 有限 | 长连接,CDN 主要做路由优化 |
| 数据库查询 | ❌ 不适用 | CDN 不处理应用层逻辑 |
💡 CDN 的本质是"用空间换时间"——在全球各地用存储空间缓存内容(花更多的存储成本),换来用户访问时的低延迟(节省大量时间)。和 Redis 缓存思路一模一样,只不过 CDN 是在地理维度上做缓存。
1.3 CDN vs 自建多机房 vs 云厂商加速——什么时候该用 CDN
"把内容搬近用户"有多种方案,CDN 只是其中之一。选错方案,要么花冤枉钱,要么解决不了问题。
方案 1:CDN(内容分发网络)
═══════════════════════════════════════════
原理:第三方在全球有上千个节点,缓存你的静态内容
成本:按流量/带宽计费,起步很低
适用:静态资源(图片/CSS/JS/视频)
不适用:需要实时数据的动态 API
落地难度:★☆☆☆☆(改个 DNS 就行)
方案 2:自建多机房
═══════════════════════════════════════════
原理:在多个地区部署完整的服务器集群
成本:每个机房都要服务器 + 运维 + 数据同步
适用:对延迟极度敏感的业务(游戏、金融交易)
不适用:小团队、流量不大的应用
落地难度:★★★★★(数据同步是噩梦)
方案 3:云厂商全球加速
═══════════════════════════════════════════
原理:利用云厂商的骨干网传输,不走公网
典型产品:AWS Global Accelerator / 阿里云全站加速
成本:按流量 + 固定费,中等
适用:动态 API 也需要加速的场景
落地难度:★★☆☆☆(配置产品即可)三种方案对比:
| 维度 | CDN | 自建多机房 | 云厂商全球加速 |
|---|---|---|---|
| 初始成本 | 低(甚至免费) | 极高 | 中等 |
| 月费(中等流量) | ¥100-2,000 | ¥50,000+ | ¥2,000-10,000 |
| 静态加速 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 动态加速 | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 落地难度 | 极低 | 极高 | 低 |
| 团队要求 | 无需专人 | 需要运维团队 | 无需专人 |
| 典型用户 | 所有网站 | 大厂、游戏 | 出海 SaaS |
务实建议:
你应该用哪种方案?
90% 的网站 → CDN 就够了
══════════════════════════
你的网站有图片、CSS、JS、视频
→ 上 CDN,改个 DNS 记录,立刻见效
→ 免费方案(Cloudflare)也够用
出海 SaaS / API 服务 → CDN + 全站加速
══════════════════════════
你的用户在全球,API 也需要低延迟
→ 静态资源走 CDN
→ API 走全站加速(DCDN / Global Accelerator)
游戏 / 金融 / 超低延迟 → 自建 + CDN
══════════════════════════
你对延迟极度敏感(< 50ms)
→ 核心业务自建多区域部署
→ 静态资源仍然用 CDN
个人博客 / 小项目 → Cloudflare 免费套餐
══════════════════════════
不花一分钱就能获得 CDN + DNS + DDoS 防护 + HTTPS
→ 没有理由不用💡 CDN 是投入产出比最高的性能优化手段——花 5 分钟配置一个 DNS CNAME 记录,就能让全球用户的访问速度提升数倍。没有其他任何优化能在这么短时间内产生如此大的效果。如果你的网站还没用 CDN,现在就去配。
第 1 章核心知识回顾:
| 概念 | 一句话解释 |
|---|---|
| RTT | 往返延迟,物理距离越远 RTT 越大,光速无法突破 |
| TTFB | 首字节到达时间 ≈ RTT × 握手轮数,直接决定体感速度 |
| CDN | 在全球部署缓存节点,让用户就近获取内容 |
| 缓存命中 | CDN 节点有缓存直接返回(HIT),没有则回源(MISS) |
| 选型建议 | 90% 场景 CDN 就够,出海 SaaS 加全站加速,超低延迟自建 |
2. CDN 架构全景
第 1 章知道了"CDN 在全球放节点"——但这些节点不是扁平的,它们有层级。理解 CDN 的三层架构和 DNS 调度机制,你才能真正理解缓存为什么没命中、回源为什么慢、节点为什么选"错"了。
2.1 三层架构:边缘节点 → 中间层 → 源站
CDN 不是"把你的文件复制到全球每一个节点"——那样太浪费空间了。它是三层金字塔结构,越靠近用户的层节点越多但缓存越少,越靠近源站的层节点越少但缓存越全。
CDN 三层架构:
┌─────────────────────────────────────────────────┐
│ Layer 3: 源站(Origin) │
│ 你的服务器(Nginx / S3 / OSS) │
│ 全量内容,唯一的数据真相来源 │
│ 全球只有 1-2 个 │
└──────────────────────┬──────────────────────────┘
│ 回源请求(MISS 时)
┌──────────────────────▼──────────────────────────┐
│ Layer 2: 中间层(Mid-tier / Shield) │
│ 区域级缓存节点(每个大洲 1-3 个) │
│ 缓存较热的内容,减少回源次数 │
│ 全球约 10-30 个 │
└────┬─────────────┬──────────────┬───────────────┘
│ │ │
┌────▼───┐ ┌────▼───┐ ┌─────▼──┐
│ Edge │ │ Edge │ │ Edge │ Layer 1: 边缘节点
│ 上海 │ │ 东京 │ │ 圣保罗 │ 离用户最近
│ POP │ │ POP │ │ POP │ 全球数百到数千个
└────────┘ └────────┘ └────────┘
▲ ▲ ▲
用户A 用户B 用户C各层的职责和处理逻辑:
边缘节点(Edge / POP)
═══════════════════════════════════
位置:各大城市的电信机房(离用户最近,通常 < 50km)
数量:数百到数千个(Cloudflare 有 300+ 个城市节点)
缓存:只缓存最热的内容(存储空间有限)
逻辑:
收到请求 → 本地有缓存?
HIT → 直接返回(最快,1-10ms)
MISS → 不直接回源!转发给中间层
中间层(Mid-tier / Origin Shield)
═══════════════════════════════════
位置:区域数据中心(每个大洲 1-3 个)
数量:10-30 个
缓存:缓存大部分热门内容(存储空间比边缘大得多)
逻辑:
收到边缘节点的请求 → 本地有缓存?
HIT → 返回给边缘节点(较快,10-50ms)
MISS → 回源站拿
源站(Origin)
═══════════════════════════════════
位置:你的服务器所在地
数量:通常 1 个(可配主备)
内容:全量数据的唯一来源
逻辑:收到请求 → 返回文件为什么需要中间层?(不能边缘直接回源吗?)
没有中间层的问题:
═══════════════════════════════════
源站在上海
全球 500 个边缘节点
→ 一个冷门文件被 10 个不同城市的用户请求
→ 500 个边缘节点中有 10 个同时回源
→ 源站收到 10 次相同请求(回源放大)
→ 热门文件可能触发数百次回源!
有中间层的好处:
═══════════════════════════════════
10 个边缘节点 MISS → 都转发给同一个区域的中间层
→ 中间层只回源 1 次,缓存后返回给 10 个边缘
→ 源站只承受 1 次请求
→ 回源请求减少 90%+💡 中间层是"源站的保护伞"。没有中间层,源站会被全球数百个边缘节点的回源请求淹没。这也是为什么配置 CDN 时你会看到"Origin Shield"选项——它就是中间层,值得开启。
2.2 DNS 调度:用户的请求如何路由到最近的节点
CDN 最关键的技术问题是:用户访问你的域名时,怎么"找到"离他最近的 CDN 节点? 答案是 DNS。
CNAME 跳转——CDN 接入的核心机制:
你的域名接入 CDN 的过程:
原来的 DNS 配置:
static.example.com → A 记录 → 1.2.3.4(你的源站 IP)
改为 CNAME 后:
static.example.com → CNAME → static.example.com.cdn.provider.com
→ DNS 解析权交给了 CDN 厂商!
→ CDN 的 DNS 根据用户位置返回最近的边缘节点 IP完整的 DNS 解析链路:
用户在巴西圣保罗,访问 static.example.com/logo.png
1. 浏览器 → 本地 DNS 缓存(有缓存就直接用,跳到第 6 步)
2. 本地 DNS → 递归 DNS 服务器(运营商的 DNS)
"static.example.com 的 IP 是什么?"
3. 递归 DNS → example.com 的权威 DNS
返回:CNAME static.example.com.cdn.provider.com
"去问 CDN 厂商的 DNS"
4. 递归 DNS → CDN 厂商的智能 DNS
CDN DNS 做三件事:
┌─────────────────────────────────────┐
│ ① 判断用户位置:巴西圣保罗 │
│ ② 查看各节点健康状态和负载 │
│ ③ 返回最近且可用的边缘节点 IP │
└─────────────────────────────────────┘
返回:203.0.113.100(圣保罗 POP 节点 IP)
5. 递归 DNS → 浏览器
"static.example.com 的 IP 是 203.0.113.100"
6. 浏览器 → 203.0.113.100(圣保罗 CDN 节点)
请求 /logo.pngCDN 智能 DNS 怎么知道"用户在哪"?
判断依据(按优先级):
① 递归 DNS 的 IP 地址
═══════════════════════════════════
用户的 DNS 请求经过运营商的递归 DNS
→ CDN 通过递归 DNS 的 IP 判断用户大致位置
→ 问题:用户用了 8.8.8.8(Google DNS),位置可能不准
② EDNS Client Subnet (ECS)
═══════════════════════════════════
DNS 协议扩展,递归 DNS 附带用户子网信息
→ CDN 能更准确地知道用户位置
→ Google DNS / Cloudflare DNS 都支持
→ 这是现代 CDN 调度精准的关键
③ 运营商 + 地域综合判断
═══════════════════════════════════
同一个城市,电信和联通用户应该去不同的节点
→ CDN 维护 IP → 运营商 的映射库
→ 电信用户 → 电信机房的节点
→ 联通用户 → 联通机房的节点💡 DNS 调度是 CDN 的"大脑"——调度得好,用户访问最近的节点,体验极佳;调度得差,中国电信的用户可能被分配到联通节点(跨运营商延迟大),或者本该去上海的用户被分配到广州。这也是为什么大厂 CDN(Cloudflare、阿里云)比小厂好的核心原因之一——调度准确度差距巨大。
2.3 Anycast vs GeoDNS vs HTTP 302 调度——三种路由策略对比
DNS 调度不是唯一方案。CDN 行业有三种主流路由策略,各有适用场景:
策略 1: GeoDNS(地理 DNS 调度)
═══════════════════════════════════
原理:CDN 的 DNS 服务器根据用户 IP 的地理位置,
返回不同地区的边缘节点 IP
优点:✅ 实现简单、技术成熟
✅ 可以精确到运营商级别(电信→电信节点)
缺点:❌ 依赖 DNS 缓存 TTL(切换节点有延迟)
❌ 用户用了公共 DNS(8.8.8.8)可能判断不准
代表:阿里云 CDN、腾讯云 CDN、AWS CloudFront
策略 2: Anycast(任播路由)
═══════════════════════════════════
原理:全球多个节点宣告相同的 IP 地址,
BGP 路由协议自动把请求路由到最近的节点
优点:✅ 天然选择最近节点(网络层级别,无需 DNS 判断)
✅ 节点故障自动切换(BGP 撤回路由即可)
✅ 天然抗 DDoS(攻击流量被分散到全球节点)
缺点:❌ 需要控制 BGP 路由(门槛高)
❌ "最近" 是网络距离,不一定是地理最近
❌ 不能做运营商级别的精细调度
代表:Cloudflare(全 Anycast 架构)、Google Cloud CDN
策略 3: HTTP 302 调度
═══════════════════════════════════
原理:用户先请求一个调度服务器,
调度服务器返回 302 重定向到最优节点
优点:✅ 调度精度最高(可根据实时负载、用户 IP 精确判断)
✅ 不受 DNS 缓存影响(每次请求都重新调度)
缺点:❌ 多一次 HTTP 往返(增加 ~1 个 RTT)
❌ 实现复杂
代表:部分点播/直播 CDN、大文件下载场景三种策略对比表:
| 维度 | GeoDNS | Anycast | HTTP 302 |
|---|---|---|---|
| 调度层级 | DNS 层 | 网络层(BGP) | 应用层(HTTP) |
| 精准度 | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 切换速度 | 受 TTL 限制 | 秒级(BGP 收敛) | 实时 |
| 额外延迟 | 无 | 无 | +1 RTT |
| 抗 DDoS | 一般 | ⭐⭐⭐⭐⭐(天然) | 一般 |
| 落地难度 | 低 | 高(需 BGP 能力) | 中 |
| 典型场景 | 国内 CDN | 全球 CDN | 视频/大文件 |
实际使用中,大多数 CDN 厂商混合使用多种策略:
Cloudflare = Anycast(主) + GeoDNS(辅)
阿里云 CDN = GeoDNS(主) + 302 调度(视频场景)
AWS CloudFront = GeoDNS + Anycast(部分节点)
→ 你不需要自己选策略——CDN 厂商帮你做了
→ 你需要关注的是:调度结果对不对(第 9 章教你怎么测)💡 作为 CDN 用户,你不需要实现调度策略——这是 CDN 厂商的核心竞争力。你需要知道的是:① Cloudflare 用 Anycast,天然抗 DDoS,适合全球业务;② 阿里云用 GeoDNS,国内调度精准,适合国内业务;③ 如果发现某些地区加速效果差,很可能是调度不准——这时候要找 CDN 厂商调整。
第 2 章核心知识回顾:
| 概念 | 一句话解释 |
|---|---|
| 三层架构 | 边缘节点(离用户近)→ 中间层(区域缓存)→ 源站(数据来源) |
| 中间层 | 聚合回源请求,保护源站不被回源洪水击垮 |
| CNAME 接入 | 把域名 CNAME 到 CDN,DNS 解析权交给 CDN 厂商 |
| GeoDNS | 根据用户 IP 地理位置返回最近节点,国内 CDN 主流 |
| Anycast | 多节点同一 IP,BGP 自动路由到最近节点,Cloudflare 主流 |
3. 缓存策略:CDN 的灵魂
CDN 的价值 = 缓存命中率。命中率 95% 意味着每 100 个请求只有 5 个需要回源——源站压力极低、用户体验极好。命中率 30% 意味着 70 个请求都要回源——CDN 就是个贵的反向代理,白花钱。
💡 本章目标:彻底理解 HTTP 缓存机制 + CDN 缓存配置 + 缓存 Key 设计 + 命中率优化四板斧。
3.1 HTTP 缓存机制回顾:Cache-Control / ETag / Last-Modified
CDN 的缓存行为建立在 HTTP 缓存协议之上——不理解 HTTP 缓存头,就无法正确配置 CDN。
强缓存 vs 协商缓存:
HTTP 缓存两大类:
强缓存(直接用,不问服务器)
═══════════════════════════════════
浏览器/CDN 看到 Cache-Control: max-age=86400
→ 文件在本地缓存 86400 秒(1 天)
→ 1 天内再请求这个文件?直接用缓存,不发任何请求!
→ 状态码:200 (from cache)
协商缓存(先问服务器"变没变")
═══════════════════════════════════
缓存过期后,浏览器/CDN 发条件请求:
→ If-None-Match: "abc123"(带上 ETag)
→ 服务器检查:文件变了吗?
→ 没变 → 返回 304 Not Modified(不传内容,省带宽)
→ 变了 → 返回 200 + 新内容Cache-Control 指令详解:
Cache-Control 是控制缓存的核心 Header:
max-age=<秒数>
═══════════════════════════════════
Cache-Control: max-age=31536000 (1 年)
→ CDN 和浏览器都可以缓存,持续 1 年
→ 适合:带哈希的静态资源(logo.a1b2c3.js)
s-maxage=<秒数>
═══════════════════════════════════
Cache-Control: s-maxage=600, max-age=60
→ CDN(共享缓存)缓存 600 秒
→ 浏览器(私有缓存)只缓存 60 秒
→ 适合:需要 CDN 灵活控制的场景
no-cache
═══════════════════════════════════
Cache-Control: no-cache
→ 不是"不缓存"!是"每次必须向服务器验证"
→ 实际效果:走协商缓存(304)
→ 适合:HTML 页面(可缓存但需要及时更新)
no-store
═══════════════════════════════════
Cache-Control: no-store
→ 真正的"不缓存"——CDN 和浏览器都不存
→ 适合:登录接口、支付页面等敏感内容
public / private
═══════════════════════════════════
public → CDN 可以缓存(共享缓存)
private → 只有浏览器能缓存,CDN 不缓存
→ 适合:private 用于包含用户个人数据的响应ETag 和 Last-Modified——协商缓存的两种方式:
| 机制 | 请求 Header | 响应 Header | 精度 |
|---|---|---|---|
| ETag | If-None-Match: "abc123" | ETag: "abc123" | 字节级(精确) |
| Last-Modified | If-Modified-Since: Wed, 15 Jan... | Last-Modified: Wed, 15 Jan... | 秒级(可能不准) |
完整的缓存判断流程:
请求到达 CDN 节点
│
▼
本地有缓存?── No ──→ 回源获取,缓存一份,返回
│
Yes
│
▼
缓存过期了?── No ──→ 直接返回缓存(HIT,最快)
│
Yes
│
▼
发条件请求给源站(带 ETag / If-Modified-Since)
│
├── 304 Not Modified → 刷新缓存 TTL,返回缓存内容
│
└── 200 OK + 新内容 → 更新缓存,返回新内容💡 对于 CDN 场景,
s-maxage是最重要的指令——它让你可以独立控制 CDN 和浏览器的缓存时长。典型配置:CDN 缓存 1 小时(s-maxage=3600),浏览器缓存 5 分钟(max-age=300)。这样 CDN 命中率高,同时浏览器端更新也不会太慢。
3.2 CDN 缓存规则配置:路径匹配、文件类型、自定义 TTL
源站的 Cache-Control 是"建议",CDN 可以选择遵守或覆盖。大多数 CDN 控制台允许你配置自己的缓存规则——CDN 规则的优先级 > 源站 Header。
CDN 缓存规则的三种匹配方式:
方式 1:按文件扩展名匹配
═══════════════════════════════════
.jpg / .png / .gif / .webp → 缓存 30 天
.css / .js → 缓存 7 天
.html → 缓存 10 分钟
.json / .xml → 不缓存
方式 2:按 URL 路径匹配
═══════════════════════════════════
/static/* → 缓存 1 年
/api/* → 不缓存
/assets/images/* → 缓存 30 天
/ → 缓存 5 分钟
方式 3:按完整 URL 匹配
═══════════════════════════════════
/index.html → 缓存 5 分钟
/sitemap.xml → 缓存 1 小时
/robots.txt → 缓存 1 天生产环境推荐的缓存 TTL 模板:
| 资源类型 | 缓存时长 | 原因 |
|---|---|---|
带哈希的 JS/CSS(app.a1b2c3.js) | 1 年(31536000s) | 文件名含哈希,内容变 = 文件名变 |
| 图片/字体/视频 | 30 天 | 不常变化 |
| HTML 页面 | 5-10 分钟 | 需要较快更新 |
| favicon.ico | 7 天 | 极少变化 |
| API 接口 | 0(不缓存) | 动态内容 |
| 用户上传内容 | 7 天 | 上传后很少修改 |
Nginx 源站配置示例(配合 CDN):
# 带哈希的静态资源——永久缓存
location ~* \.(js|css)$ {
# 文件名包含哈希时使用
add_header Cache-Control "public, max-age=31536000, immutable";
}
# 图片——长缓存
location ~* \.(jpg|jpeg|png|gif|webp|svg|ico)$ {
add_header Cache-Control "public, max-age=2592000"; # 30 天
}
# HTML——短缓存 + CDN 独立控制
location ~* \.html$ {
add_header Cache-Control "public, s-maxage=600, max-age=300";
# CDN 缓存 10 分钟,浏览器缓存 5 分钟
}
# API——不缓存
location /api/ {
add_header Cache-Control "no-store";
}💡
immutable是一个被低估的指令。Cache-Control: immutable告诉浏览器"这个文件永远不会变"——用户刷新页面时,浏览器不会发协商请求(连 304 都省了)。对于带哈希的静态资源,加上immutable能消除不必要的 304 请求。
3.3 缓存 Key 设计:忽略参数、Header 变体、Cookie 分区
缓存 Key 是 CDN 用来查找缓存的"索引"。Key 设计不好,同样的文件被当成不同的缓存条目——命中率暴跌。
什么是缓存 Key?
默认的缓存 Key = URL 全路径(包括查询参数)
请求 1: /logo.png?v=1 → Key: /logo.png?v=1 → MISS → 缓存
请求 2: /logo.png?v=2 → Key: /logo.png?v=2 → MISS → 又缓存一份!
请求 3: /logo.png?from=home → Key: /logo.png?from=home → MISS → 又缓存一份!
→ 同一个文件,3 个不同的缓存条目
→ 命中率:0%(因为没人请求完全相同的 URL)问题 1:URL 参数导致缓存分裂
典型场景:营销追踪参数
/product.html?utm_source=google
/product.html?utm_source=twitter
/product.html?utm_source=email
/product.html?fbclid=abc123
/product.html?ref=partner
→ 5 个 URL,内容完全一样
→ 但 CDN 认为是 5 个不同的资源
→ 缓存命中率直接腰斩
解决方案:配置 CDN 忽略指定参数
→ 忽略 utm_*, fbclid, ref, from 等追踪参数
→ 缓存 Key 只用 /product.html
→ 5 个请求命中同一份缓存问题 2:Vary Header 的坑
Vary Header 告诉 CDN:"不同的请求头值 = 不同的缓存"
响应头:Vary: Accept-Encoding
→ 合理!gzip 和 br 压缩版本确实不同
→ CDN 缓存两份:一份 gzip,一份 brotli
响应头:Vary: User-Agent
→ 灾难!User-Agent 有几千种不同值
→ 相当于每种浏览器版本一份缓存
→ 命中率 → 趋近于 0%
响应头:Vary: Cookie
→ 更大的灾难!每个用户 Cookie 都不同
→ 相当于不缓存
安全的 Vary 值:
✅ Accept-Encoding(gzip/br 变体)
✅ Accept(HTML vs JSON 内容协商)
❌ User-Agent、Cookie、Authorization问题 3:Cookie 对缓存的影响
很多源站的响应默认带 Set-Cookie:
响应头:Set-Cookie: session_id=abc123
CDN 看到 Set-Cookie 后的行为(各厂商不同):
→ Cloudflare:默认不缓存带 Set-Cookie 的响应
→ 阿里云 CDN:可配置是否忽略 Cookie
→ AWS CloudFront:默认不缓存
解决方案:
① 静态资源的响应不要带 Set-Cookie
② 用独立域名(static.example.com)提供静态资源
③ CDN 配置中忽略 Cookie💡 忽略无关的 URL 参数和 Cookie 是提升命中率最立竿见影的操作——很多网站的命中率从 40% 直接跳到 80%+,只是因为做了这一件事。配 CDN 后第一件事就检查:你的请求 URL 上有没有追踪参数?源站响应有没有带 Set-Cookie?
3.4 缓存命中率优化:从 60% 到 95% 的实战技巧
把前面三节的知识汇总,这是一份缓存命中率优化清单——从最容易做到的开始:
优化 1:静态资源用独立域名(立刻做)
═══════════════════════════════════
❌ example.com/images/logo.png ← 主域名,请求会带 Cookie
✅ static.example.com/logo.png ← 独立域名,无 Cookie 污染
效果:命中率 +10-20%(消除 Cookie 导致的缓存失效)
优化 2:静态资源文件名加哈希(构建工具自动做)
═══════════════════════════════════
❌ /js/app.js ← 文件名不变,TTL 不敢设太长
✅ /js/app.a1b2c3d4.js ← 内容变 → 哈希变 → 文件名变
效果:TTL 可以设 1 年,命中率 +20%
优化 3:忽略无关 URL 参数(CDN 控制台配置)
═══════════════════════════════════
忽略列表:utm_source, utm_medium, utm_campaign,
fbclid, gclid, ref, from, _t, timestamp
效果:命中率 +10-30%(取决于你的 URL 参数多不多)
优化 4:内容预热(大促 / 发布前做)
═══════════════════════════════════
CDN 默认是"被动缓存"——第一个请求一定是 MISS
预热 = 主动把内容推到 CDN 节点
方式 1:CDN 控制台提交预热任务
方式 2:脚本批量 curl 所有静态资源 URL
方式 3:Cloudflare API 批量预热
效果:消除"冷启动"导致的 MISS,大促不卡
优化 5:合理设置 TTL(不要一刀切)
═══════════════════════════════════
不变的资源(带哈希的 JS/CSS)→ 1 年
很少变的资源(图片/字体) → 30 天
偶尔变的资源(HTML) → 10 分钟
频繁变的资源(API) → 不缓存
效果:命中率 +5-10%
优化 6:消除 Vary 头污染(检查源站配置)
═══════════════════════════════════
检查:curl -I https://static.example.com/logo.png
看 Vary 头的值——只允许 Accept-Encoding
效果:命中率 +5-15%(看 Vary 头有多"脏")优化前后对比:
| 指标 | 优化前 | 优化后 |
|---|---|---|
| 缓存命中率 | 40-60% | 90-98% |
| 回源带宽 | 100 Mbps | 5-15 Mbps |
| 源站 QPS | 5,000 | 200-500 |
| 用户 TTFB | 200-500ms | 10-50ms |
| CDN 月费 | ¥2,000(回源流量大) | ¥800(回源少) |
💡 缓存命中率是 CDN 的核心 KPI。90% 以下说明有配置问题,95%+ 是健康的标准。做完上面 6 项优化,大多数网站都能到 95%+。如果还上不去,检查是不是有"长尾冷内容"太多(文件总量大但每个文件访问量低)——这种情况考虑合并小文件或开启中间层缓存。
第 3 章核心知识回顾:
| 概念 | 一句话解释 |
|---|---|
| 强缓存 | max-age 未过期时直接用缓存,不发请求 |
| 协商缓存 | 过期后发条件请求(ETag/304),确认没变就继续用 |
| s-maxage | 独立控制 CDN 缓存时长,不影响浏览器 |
| 缓存 Key | CDN 查找缓存的索引,默认是完整 URL(含参数) |
| 命中率优化 | 独立域名 + 哈希命名 + 忽略参数 + 预热 + TTL + Vary |
4. 回源机制与源站保护
缓存没命中的时候,CDN 要回源站拿内容——这个过程叫"回源"。回源是 CDN 系统中延迟最高、风险最大的环节:回源慢用户就等得久,回源请求太多源站就被打爆。
4.1 回源流程拆解:什么时候 CDN 要找源站要内容
CDN 触发回源的四种场景:
场景 1:首次请求(Cold MISS)
═══════════════════════════════════
一个全新的 URL 从未被 CDN 缓存过
→ 第一个用户请求一定是 MISS → 回源
→ 解决:预热(提前把内容推到 CDN)
场景 2:缓存过期(TTL Expired)
═══════════════════════════════════
缓存已经存在,但 TTL 到期了
→ CDN 发协商请求:If-None-Match / If-Modified-Since
→ 源站没变 → 304(不传内容,只刷新 TTL)
→ 源站变了 → 200 + 新内容
→ 解决:设置合理的 TTL
场景 3:缓存被淘汰(Eviction)
═══════════════════════════════════
边缘节点磁盘满了,LRU 淘汰最久未访问的缓存
→ 冷门文件被淘汰后再被请求 → MISS → 回源
→ 解决:开启中间层(Origin Shield)
场景 4:手动刷新(Purge)
═══════════════════════════════════
你在 CDN 控制台主动刷新/清除了缓存
→ 下一个请求 → MISS → 回源
→ 这是预期行为,用于紧急更新内容回源请求长什么样?
# CDN 节点回源时发出的请求(和普通 HTTP 请求类似,但有特殊 Header)
GET /images/logo.png HTTP/1.1
Host: origin.example.com
X-Forwarded-For: 203.0.113.50 # 原始用户 IP
Via: 1.1 cdn-edge-sh01 # CDN 节点标识
If-None-Match: "abc123" # 协商缓存(如有)
Accept-Encoding: gzip, br # 压缩支持回源的成本意识:
回源产生两种成本:
① 延迟成本
═══════════════════════════════════
边缘节点在上海,源站在上海 → 回源延迟 ~10ms
边缘节点在圣保罗,源站在上海 → 回源延迟 ~350ms
→ 中间层可以缩短:圣保罗边缘 → 美东中间层(~50ms)→ 上海源站
② 流量成本
═══════════════════════════════════
大多数 CDN 厂商:回源流量另外计费!
→ 回源流量通常比 CDN 分发流量贵 2-5 倍
→ 命中率每提高 1%,回源流量就少 1%4.2 回源策略:主备源站、权重轮询、故障转移
源站不只一个——配置多源站和故障转移策略,是生产环境的基本操作。
策略 1:主备源站
═══════════════════════════════════
主源站:origin-1.example.com(所有回源请求发到这里)
备源站:origin-2.example.com(主源站挂了才用)
触发切换条件:
→ 主源站连续 3 次返回 5xx
→ 主源站连接超时(超过 30 秒)
→ 主源站健康检查失败
适用:大多数网站——简单可靠
策略 2:权重轮询
═══════════════════════════════════
源站 A:origin-a.example.com(权重 70%)
源站 B:origin-b.example.com(权重 30%)
→ 70% 的回源请求发给 A,30% 发给 B
→ 可以用于灰度发布(新版源站权重 10% 试跑)
适用:多机房部署、灰度场景
策略 3:就近回源
═══════════════════════════════════
亚洲回源 → origin-asia.example.com
欧洲回源 → origin-eu.example.com
美洲回源 → origin-us.example.com
→ CDN 根据边缘节点所在区域选择最近的源站
→ 减少跨大洲回源延迟
适用:全球部署了多个源站的大型应用CDN 的健康检查机制:
CDN 怎么知道源站是否健康?
① 被动检测(默认)
═══════════════════════════════════
正常回源时如果收到 5xx / 超时
→ 标记该源站为异常
→ 连续 N 次异常后切换到备源站
→ 恢复后自动切回
② 主动健康检查(推荐开启)
═══════════════════════════════════
CDN 每隔 30 秒向源站发 HEAD 请求
→ 返回 200 → 健康
→ 返回 5xx 或超时 → 不健康
→ 不健康的源站直接从回源列表移除
→ 比被动检测更快发现故障(用户无感)💡 生产环境必须配备源站。单一源站挂了,所有 CDN 节点的缓存过期后就无法更新——相当于全站逐渐失效。配一个备源站可能只需要一台廉价服务器做文件同步,成本极低但关键时刻能救命。
4.3 回源优化:合并回源、Range 回源、预热与刷新
回源不可避免,但可以让回源更高效——减少次数、减少流量、减少延迟。
合并回源(Request Coalescing / Collapsed Forwarding):
问题场景:
═══════════════════════════════════
一个新文件(未缓存),1 秒内 100 个用户同时请求
→ 没有合并回源:CDN 向源站发 100 次相同请求 ❌
→ 源站压力 × 100
有合并回源:
═══════════════════════════════════
第 1 个请求 → MISS → 发起回源
第 2-100 个请求 → 发现已有回源请求在进行中
→ 排队等待,不重复回源
→ 第 1 个回源返回后 → 缓存 → 同时响应所有 100 个等待中的请求
结果:100 个请求只触发 1 次回源 ✅
配置:大多数 CDN 默认开启,确认即可
→ Cloudflare:默认开启
→ 阿里云 CDN:需手动开启"回源合并"Range 回源(大文件优化):
问题场景:
═══════════════════════════════════
用户请求一个 2GB 的视频文件
→ CDN 没缓存 → 回源拉完整个 2GB?
→ 用户可能只看了前 30 秒就关掉了 → 浪费!
Range 回源:
═══════════════════════════════════
CDN 不一次拉完,按需分段回源:
→ 用户请求 0-1MB → CDN 回源 Range: bytes=0-1048576
→ 用户继续播放 → CDN 继续回源下一段
→ 用户关掉了 → 停止回源(只拉了实际用到的部分)
好处:
✅ 首字节到达更快(不等完整文件传完)
✅ 节省回源带宽(只拉用户实际需要的部分)
✅ 支持视频拖拽(Seek 到任意位置直接回源那段)
前提:源站必须支持 Range 请求
→ Nginx、S3、OSS 默认支持
→ 自定义服务器需要实现 206 Partial Content预热 vs 刷新——两个相反的操作:
| 操作 | 含义 | 效果 | 使用场景 |
|---|---|---|---|
| 预热(Prefetch) | 主动把内容推到 CDN 节点 | 第一个用户就能 HIT | 新上线、大促前 |
| 刷新(Purge) | 主动清除 CDN 上的缓存 | 下一个请求会 MISS | 内容更新、紧急修复 |
预热和刷新的正确用法:
发布新版前端:
═══════════════════════════════════
1. 部署新文件到源站(新哈希名,不影响旧缓存)
2. 预热:把新 JS/CSS 推到 CDN(curl 或 API)
3. 更新 HTML(引用新的哈希文件名)
4. 刷新:清除旧 HTML 缓存
→ 用户拿到新 HTML → 加载新 JS/CSS(已预热,秒加载)
紧急修复线上 Bug:
═══════════════════════════════════
1. 修复代码,部署到源站
2. 刷新:清除受影响的 URL 缓存
→ CDN 下次请求回源拿到新内容
→ 注意:刷新有全球生效延迟(通常 1-5 分钟)💡 "先预热再刷新"是版本发布的黄金顺序。先把新文件推到 CDN(预热),确保全球节点都有了,再刷新旧 HTML 让用户切到新版本——这样用户永远不会遇到"新 HTML 引用了新 JS,但 CDN 上还没有新 JS"的断档。
4.4 源站保护:防盗链、IP 白名单、鉴权 URL
你的源站 IP 不应该被直接访问——否则别人绕过 CDN 直连源站,你的缓存白做了,源站还可能被攻击。
防盗链(Referer 防护):
问题:别人在自己的网站上引用你的图片
═══════════════════════════════════
<img src="https://static.你的域名.com/美女.jpg">
→ 他的用户看图片,你付 CDN 流量费
→ 叫"盗链"
解决:Referer 白名单
═══════════════════════════════════
CDN 检查请求的 Referer Header:
→ Referer 在白名单(你自己的域名)→ 允许
→ Referer 不在或为空 → 返回 403 Forbidden
配置示例(CDN 控制台):
白名单:example.com, *.example.com
是否允许空 Referer:否(防止直接访问)回源 IP 白名单(源站防护):
问题:源站 IP 被泄露,攻击者绕过 CDN 直连
═══════════════════════════════════
→ CDN 被绕过,所有防护失效
→ 源站被 DDoS 打爆
解决:源站的防火墙只允许 CDN 的回源 IP
═══════════════════════════════════
# Nginx 配置(只允许 CDN 回源 IP)
allow 103.21.244.0/22; # Cloudflare IP 段
allow 103.22.200.0/22;
allow 104.16.0.0/13;
deny all; # 拒绝所有其他 IP
各 CDN 厂商的回源 IP 列表:
→ Cloudflare: https://www.cloudflare.com/ips/
→ 阿里云 CDN: 控制台查看回源 IP 段
→ AWS CloudFront: aws ip-ranges.json鉴权 URL(签名防盗链):
问题:Referer 防盗链可以伪造
═══════════════════════════════════
→ Referer 是 HTTP Header,很容易被修改
→ 高价值资源(付费视频/下载)需要更强的保护
解决:URL 签名——带有限时 Token 的 URL
═══════════════════════════════════
原始 URL:/video/premium.mp4
签名 URL:/video/premium.mp4?sign=abc123&t=1705315200
签名生成规则(服务端):
sign = MD5(secret_key + 文件路径 + 过期时间戳)
t = 过期时间戳(Unix timestamp)
CDN 验证逻辑:
① 检查 t 是否过期 → 过期 → 403
② 用相同规则计算签名 → 不匹配 → 403
③ 签名正确且未过期 → 允许访问
优势:
✅ 无法伪造(不知道 secret_key)
✅ 有时间限制(链接过期失效)
✅ 可以绑定用户 IP(防止分享链接)💡 安全防护要分层:Referer 防盗链挡住 90% 的普通盗链(成本低、简单);回源 IP 白名单防止源站被绕过(必须做);鉴权 URL 保护高价值资源(付费内容必须做)。三者不是互斥的,应该叠加使用。
第 4 章核心知识回顾:
| 概念 | 一句话解释 |
|---|---|
| 回源四场景 | 首次请求、缓存过期、LRU 淘汰、手动刷新 |
| 主备源站 | 主源异常自动切备源,生产环境必须配 |
| 合并回源 | 多个 MISS 只发一次回源请求,防止"回源风暴" |
| Range 回源 | 大文件分段拉取,节省带宽、降低首字节延迟 |
| 先预热再刷新 | 版本发布黄金顺序,避免 CDN 断档 |
| 源站保护 | Referer 防盗链 + IP 白名单 + 签名 URL 三层防护 |
5. HTTPS 与安全加速
2024 年不上 HTTPS 基本等于"不存在"——Chrome 标记 HTTP 为"不安全"、搜索引擎降权、HTTP/2 和 HTTP/3 强制要求 HTTPS。CDN 上部署 HTTPS 不只是"上个证书"——TLS 握手本身可能增加 1-2 个 RTT,优化不好反而变慢。
5.1 CDN 上部署 HTTPS:证书管理与 SNI
CDN 的 HTTPS 架构——两段加密:
用户 ←──── HTTPS ────→ CDN 边缘节点 ←──── HTTPS ────→ 源站
(用户到边缘的加密) (边缘到源站的加密)
两段可以独立配置:
→ 用户到 CDN:必须 HTTPS(用户体验 + 安全)
→ CDN 到源站:可选 HTTPS 或 HTTP(看安全要求)CDN 回源协议选择:
| 回源协议 | 安全性 | 性能 | 适用场景 |
|---|---|---|---|
| HTTPS 回源 | ⭐⭐⭐⭐⭐ | 稍慢(TLS 握手) | 敏感数据(登录/支付) |
| HTTP 回源 | ⭐⭐ | 更快 | 纯静态资源(图片/CSS) |
| 协议跟随 | 跟随用户请求 | 视情况 | 混合场景 |
证书部署方式:
方式 1:CDN 厂商免费证书(推荐入门)
═══════════════════════════════════
→ Cloudflare:自动签发,点一下就开启 HTTPS
→ 阿里云 CDN:免费 DV 证书,一键申请
→ 优点:零成本、自动续期
→ 缺点:只支持单域名
方式 2:上传自有证书
═══════════════════════════════════
→ 上传证书文件(.pem)+ 私钥(.key)到 CDN 控制台
→ 支持通配符证书(*.example.com)
→ 需要自己管理续期
→ 适合:多子域名、企业级证书
方式 3:Let's Encrypt 自动化
═══════════════════════════════════
→ 用 certbot 自动签发 + 自动续期
→ 通过 DNS-01 验证(配合 CDN 的 DNS API)
→ 适合:自动化运维团队SNI(Server Name Indication)——一个 IP 多个证书:
问题:CDN 边缘节点一个 IP 要服务数百万个域名
═══════════════════════════════════
→ 传统 HTTPS:一个 IP 只能绑一个证书
→ CDN 有几千个域名,不可能给每个域名分 IP
解决:SNI 扩展
═══════════════════════════════════
TLS 握手时,客户端在 ClientHello 中告诉服务器:
"我要访问的是 static.example.com"
→ CDN 根据域名找到对应的证书
→ 一个 IP 可以服务无数个域名
兼容性:所有现代浏览器都支持
唯一问题:极老的客户端(IE6/WinXP)不支持 SNI
→ 2024 年可以无视这个问题5.2 TLS 优化三板斧:OCSP Stapling / TLS 1.3 / Session Resumption
TLS 握手是 HTTPS 的性能瓶颈——每次新连接需要 1-2 个额外 RTT。以下三项优化能把 TLS 开销降到最低:
优化 1:TLS 1.3(最重要)
═══════════════════════════════════
TLS 1.2 握手:2 个 RTT
TLS 1.3 握手:1 个 RTT
TLS 1.3 0-RTT:0 个 RTT(重复连接)
→ 每次连接省 1 个 RTT
→ 跨大洲连接(RTT 200ms)省 200ms——用户能感知的差距
配置:CDN 控制台开启 TLS 1.3(大多数默认已开启)
兼容性:所有现代浏览器均支持
优化 2:OCSP Stapling(消除证书验证延迟)
═══════════════════════════════════
问题:浏览器需要验证证书是否被吊销
→ 向 CA 的 OCSP 服务器发请求
→ OCSP 服务器可能在国外 → 额外 100-500ms 延迟
→ 有时 OCSP 服务器慢或挂了 → 更离谱的延迟
解决:OCSP Stapling
→ CDN 节点定期获取 OCSP 响应并缓存
→ TLS 握手时直接把 OCSP 响应"钉"在证书上发给浏览器
→ 浏览器不需要再单独查询 OCSP → 省一次外部请求
Nginx 配置:
ssl_stapling on;
ssl_stapling_verify on;
CDN 配置:大多数厂商默认开启
优化 3:Session Resumption(跳过重复握手)
═══════════════════════════════════
问题:用户打开多个页面,每个页面都要 TLS 握手?
解决 A:Session ID
→ 服务器缓存 Session 状态
→ 客户端重连时携带 Session ID → 跳过完整握手
→ 问题:CDN 有数百个节点,Session 不共享
解决 B:Session Ticket(推荐)
→ 服务器把 Session 状态加密后发给客户端保存
→ 客户端重连时携带 Ticket → 任何节点都能解密恢复
→ 不需要节点间共享状态 → 完美适配 CDN 架构
效果:重复连接 TLS 握手从 1 RTT → 0 RTTTLS 优化效果对比:
| 配置 | 首次连接延迟 | 重复连接延迟 | 推荐 |
|---|---|---|---|
| TLS 1.2 无优化 | +2 RTT | +1 RTT | ❌ |
| TLS 1.3 | +1 RTT | +1 RTT | ✅ |
| TLS 1.3 + Session Ticket | +1 RTT | +0 RTT | ✅✅ |
| TLS 1.3 + 0-RTT | +1 RTT | +0 RTT | ⚠️ 有安全风险 |
💡 TLS 1.3 + OCSP Stapling + Session Ticket 是标配。大多数 CDN 厂商默认开启,你需要做的只是确认。在 CDN 控制台检查这三项:① TLS 最低版本设为 1.2(兼容)或 1.3(激进)② OCSP Stapling 开启 ③ Session Ticket 开启。
5.3 安全防护:WAF、DDoS 防护、Bot 管理
CDN 不只是"加速器"——因为所有流量都经过 CDN,它是天然的安全屏障。现代 CDN 厂商都在边缘节点集成了安全能力。
CDN 的三层安全防护:
Layer 1: DDoS 防护(网络层/传输层)
═══════════════════════════════════
攻击类型:SYN Flood / UDP Flood / DNS 放大攻击
防护原理:
→ Anycast 把攻击流量分散到全球节点
→ 每个节点过滤异常流量
→ 单节点承受 1Tbps 攻击,分散到 300 个节点 = 每个只需处理 3.3Gbps
效果:Cloudflare Free 套餐就包含无限 DDoS 防护
配置:无需配置,默认生效
Layer 2: WAF(应用层防火墙)
═══════════════════════════════════
攻击类型:SQL 注入 / XSS / CSRF / 文件包含
防护原理:
→ 边缘节点检查每个 HTTP 请求的内容
→ 匹配 OWASP Top 10 攻击规则
→ 命中规则 → 拦截或记录
典型规则:
→ 请求中包含 ' OR 1=1 -- → 拦截(SQL 注入)
→ 请求中包含 <script> → 拦截(XSS)
→ 非法文件上传 → 拦截
配置:CDN 控制台开启 WAF,选择托管规则集
费用:Cloudflare Pro($20/月)起、阿里云 WAF 另购
Layer 3: Bot 管理(机器人防护)
═══════════════════════════════════
问题:不是所有 Bot 都是坏的
→ 好 Bot:Googlebot(搜索索引)、监控服务
→ 坏 Bot:爬虫、撞库、囤货抢购、API 滥用
防护手段:
→ JS Challenge:要求执行 JavaScript(纯 Bot 做不到)
→ CAPTCHA Challenge:人机验证
→ 行为分析:鼠标轨迹、点击频率、浏览模式
→ IP 信誉库:已知恶意 IP 直接拦截
配置:设定安全级别(低/中/高/Under Attack)各 CDN 厂商的安全能力对比:
| 能力 | Cloudflare Free | Cloudflare Pro | 阿里云 CDN | AWS CloudFront |
|---|---|---|---|---|
| DDoS 防护 | ✅ 无限 | ✅ 无限 | ✅ 基础 | ✅ AWS Shield |
| WAF | 基础规则 | ✅ OWASP 全集 | 需购 WAF | 需购 AWS WAF |
| Bot 管理 | JS Challenge | ✅ 高级 | 基础 | 需额外配置 |
| 速率限制 | 基础 | ✅ 自定义 | ✅ 自定义 | ✅ 自定义 |
| 月费起步 | 免费 | $20 | ~¥100 | 按用量 |
💡 CDN 的安全价值常被低估。很多公司单独购买 DDoS 防护和 WAF 服务,每月花费数万元——而 Cloudflare Pro 套餐 $20/月就包含了全部。如果你已经在用 CDN,先检查它自带的安全能力,很可能不需要额外购买安全产品。
第 5 章核心知识回顾:
| 概念 | 一句话解释 |
|---|---|
| 两段加密 | 用户→CDN 和 CDN→源站 的 HTTPS 可独立配置 |
| SNI | 一个 IP 服务多个域名的 HTTPS,现代标准 |
| TLS 1.3 | 握手从 2 RTT 降到 1 RTT,必须开启 |
| OCSP Stapling | 消除证书验证的额外网络请求延迟 |
| Session Ticket | 重复连接跳过 TLS 握手,适配 CDN 多节点架构 |
| CDN 安全 | DDoS + WAF + Bot 管理三层防护,用 CDN 就能获得 |
6. 全站加速(动态加速)
前面五章讲的都是"静态加速"——把图片、CSS、JS 缓存到边缘节点。但 API 接口返回的数据每次都不同、不能缓存——怎么加速?这就是"动态加速"(DCDN)。
6.1 静态加速 vs 动态加速——区别在哪
静态加速(CDN 传统能力)
═══════════════════════════════════
加速原理:缓存内容到边缘节点
适用内容:图片、CSS、JS、视频、字体
核心指标:缓存命中率(越高越好)
延迟来源:边缘节点到用户的距离
用户 → CDN 边缘(有缓存,直接返回)
延迟:1-10ms ✅
动态加速(DCDN / 全站加速)
═══════════════════════════════════
加速原理:优化传输路径(不缓存内容)
适用内容:API 接口、登录、搜索、个性化页面
核心指标:回源延迟(越低越好)
延迟来源:源站处理时间 + 网络传输时间
用户 → CDN 边缘 → 优化路径 → 源站 → 返回
延迟:比直连源站快 30-60%为什么动态加速比直连快?(明明都要回源)
直连源站:
═══════════════════════════════════
圣保罗用户 ─── 公网 ──→ 上海源站
→ 公网路由不可控,可能绕道、拥堵
→ 跨运营商、跨国交换节点多
→ RTT: 350ms(不稳定,有时 500ms+)
动态加速:
═══════════════════════════════════
圣保罗用户 → 圣保罗 CDN 节点
→ CDN 骨干网(专线/优化路由)
→ 上海 CDN 节点 → 上海源站
→ 用 CDN 厂商的骨干网替代公网
→ 路由优化、TCP 优化、连接复用
→ RTT: 200ms(更稳定)6.2 动态路径优化:智能路由、TCP 优化、连接复用
动态加速的三大核心技术:
技术 1:智能路由(最重要)
═══════════════════════════════════
CDN 厂商在全球节点间建立了"专线网络"
→ 实时探测各条路径的延迟和丢包率
→ 自动选择当前最快的路径转发请求
类比:公网是普通公路(红灯、堵车、绕路)
CDN 骨干网是高速公路(直达、不堵)
效果:跨大洲延迟降低 30-50%
技术 2:TCP 优化
═══════════════════════════════════
问题:TCP 在长距离高延迟链路上性能差
→ 慢启动需要好几个 RTT 才能跑满带宽
→ 丢包后窗口减半,恢复慢
CDN 的 TCP 优化:
→ 边缘节点代理 TCP 连接(拆成两段短连接)
→ 用户 ↔ 边缘:低延迟短连接,快速握手
→ 边缘 ↔ 源站:长连接复用,已经过慢启动阶段
→ 定制拥塞控制算法(BBR 等)
效果:小文件传输速度提升 2-3 倍
技术 3:连接复用(Keep-Alive / 长连接池)
═══════════════════════════════════
问题:每个用户请求都新建 TCP + TLS 连接?
→ 握手成本太高(3-5 个 RTT)
CDN 连接复用:
→ 边缘节点维护到源站的长连接池
→ 多个用户请求复用同一条连接
→ 省掉了 TCP + TLS 握手
效果:消除源站方向的握手延迟6.3 全站加速实战:API 接口 + 静态资源混合加速配置
实际项目中,你的网站既有静态资源又有 API——需要分开配置。
方案 1:双域名分流(推荐)
═══════════════════════════════════
static.example.com → 普通 CDN(静态加速)
→ 配置缓存规则、长 TTL
→ 命中率目标 95%+
api.example.com → DCDN(动态加速)
→ 不缓存,走智能路由
→ 优化传输路径
好处:
✅ 缓存策略互不干扰
✅ 静态域名用便宜的 CDN 计费
✅ 动态域名用专业的 DCDN 优化
方案 2:同域名路径分流
═══════════════════════════════════
example.com/static/* → 走缓存(静态加速)
example.com/api/* → 不缓存(动态加速)
CDN 配置:
→ /static/* 路径:缓存 30 天
→ /api/* 路径:回源,开启动态加速
→ / 路径:缓存 5 分钟(HTML)
好处:不需要改代码中的域名引用
缺点:Cookie 可能污染静态资源缓存各厂商全站加速产品:
| 厂商 | 产品名 | 特点 |
|---|---|---|
| Cloudflare | Argo Smart Routing | 通过 Cloudflare 骨干网转发,延迟降低 30% |
| 阿里云 | 全站加速 DCDN | 智能路由 + TCP 优化 + WebSocket 支持 |
| AWS | Global Accelerator | Anycast + AWS 骨干网,适合 API 加速 |
| 腾讯云 | ECDN | 动静混合加速,自动识别内容类型 |
💡 90% 的网站只需要静态 CDN。动态加速(DCDN)的费用通常是静态 CDN 的 3-5 倍,只有当你的用户分布全球且 API 延迟是核心痛点时才值得上。先把静态资源的缓存命中率做到 95%+,再考虑 API 加速。
第 6 章核心知识回顾:
| 概念 | 一句话解释 |
|---|---|
| 静态加速 | 缓存内容到边缘节点,命中率是核心 |
| 动态加速 | 不缓存内容,优化传输路径(骨干网替代公网) |
| 智能路由 | 实时探测选择最快路径,跨大洲延迟降低 30-50% |
| TCP 优化 | 边缘代理连接 + 定制拥塞控制,小文件速度翻倍 |
| 双域名分流 | static 走缓存 CDN,api 走动态 DCDN,互不干扰 |
7. 边缘计算与 Edge Functions
CDN 节点过去只做一件事:缓存文件、返回文件。但现在,你可以在边缘节点上运行代码——不需要回源站,直接在离用户最近的地方处理请求。这就是"边缘计算"。
7.1 什么是边缘计算:从"缓存代理"到"计算节点"
传统 CDN 节点的能力:
═══════════════════════════════════
收到请求 → 有缓存就返回,没有就回源
→ 只做"搬运",不做"计算"
边缘计算的能力:
═══════════════════════════════════
收到请求 → 运行你写的代码 → 返回结果
→ 可以修改请求、改写响应、做逻辑判断
→ 不需要回源站
→ 响应时间 = 边缘节点到用户的延迟(1-10ms)
能做什么?
→ URL 重写和重定向
→ A/B 测试(在边缘分流,不需要后端改代码)
→ 地理定向(根据用户国家返回不同内容)
→ 请求鉴权(JWT 验证在边缘完成)
→ HTML 注入(在边缘往 HTML 里插入脚本/样式)
→ API 聚合(在边缘合并多个后端 API 的结果)7.2 主流方案对比:Cloudflare Workers / Vercel Edge / AWS Lambda@Edge
Cloudflare Workers(推荐入门)
═══════════════════════════════════
运行时:V8 Isolates(和 Chrome 相同的 JS 引擎)
语言:JavaScript / TypeScript / Wasm
冷启动:0ms(V8 Isolate 没有冷启动问题)
部署范围:300+ 全球节点
免费额度:10 万次/天
配套服务:KV(键值存储)、D1(SQLite)、R2(对象存储)
优势:
✅ 冷启动为零,响应极快
✅ 免费额度够个人项目用
✅ 配套存储服务丰富
✅ 部署简单(wrangler deploy 一条命令)
Vercel Edge Functions
═══════════════════════════════════
运行时:Edge Runtime(基于 V8)
语言:JavaScript / TypeScript
冷启动:极低
部署范围:与 Vercel 网络一致
免费额度:包含在 Hobby 套餐中
优势:
✅ 与 Next.js 深度集成(middleware.ts 自动部署到边缘)
✅ 对前端开发者最友好
缺点:绑定 Vercel 平台
AWS Lambda@Edge / CloudFront Functions
═══════════════════════════════════
运行时:Node.js(Lambda@Edge)/ JavaScript(CF Functions)
冷启动:Lambda@Edge 有冷启动(100-500ms)
部署范围:CloudFront 全球节点
优势:
✅ AWS 生态集成
✅ CloudFront Functions 轻量级(无冷启动)
缺点:Lambda@Edge 冷启动影响体验三者对比:
| 维度 | Cloudflare Workers | Vercel Edge | Lambda@Edge |
|---|---|---|---|
| 冷启动 | 0ms | ~0ms | 100-500ms |
| 免费额度 | 10 万次/天 | 含 Hobby | 100 万次/月 |
| 配套存储 | KV / D1 / R2 | Vercel KV | DynamoDB |
| 部署便捷 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| 适合场景 | 通用边缘计算 | Next.js 项目 | AWS 重度用户 |
7.3 边缘计算实战:A/B 测试、地理定向、请求改写
三个最常见的边缘计算用例(Cloudflare Workers 示例):
实战 1:A/B 测试(在边缘分流,零后端改动)
// 边缘 A/B 测试:50% 用户看新版首页,50% 看旧版
export default {
async fetch(request) {
const url = new URL(request.url);
// 用 Cookie 保持用户分组一致
const cookie = request.headers.get('Cookie') || '';
let variant = cookie.includes('ab=new') ? 'new' :
cookie.includes('ab=old') ? 'old' : null;
// 新用户随机分组
if (!variant) {
variant = Math.random() < 0.5 ? 'new' : 'old';
}
// 根据分组修改请求路径
if (variant === 'new' && url.pathname === '/') {
url.pathname = '/new-homepage';
}
const response = await fetch(url, request);
const newResponse = new Response(response.body, response);
newResponse.headers.set('Set-Cookie', `ab=${variant}; Path=/; Max-Age=86400`);
return newResponse;
}
};实战 2:地理定向(根据国家返回不同内容)
// 根据用户国家重定向到对应站点
export default {
async fetch(request) {
const country = request.cf?.country || 'US';
const countryMap = {
'CN': 'https://cn.example.com',
'JP': 'https://jp.example.com',
'KR': 'https://kr.example.com',
};
if (countryMap[country]) {
return Response.redirect(countryMap[country] + new URL(request.url).pathname, 302);
}
return fetch(request); // 默认回源
}
};实战 3:请求改写(在边缘添加 Header / 修改响应)
// 添加安全 Header + 注入性能监控脚本
export default {
async fetch(request) {
const response = await fetch(request);
const newResponse = new Response(response.body, response);
// 添加安全 Header
newResponse.headers.set('X-Content-Type-Options', 'nosniff');
newResponse.headers.set('X-Frame-Options', 'DENY');
newResponse.headers.set('Strict-Transport-Security', 'max-age=31536000');
return newResponse;
}
};💡 边缘计算的核心价值是"在用户身边做决策"。A/B 测试、地理定向、鉴权这些操作,传统方案需要请求到达源站才能处理——跨大洲延迟 200ms。在边缘做,延迟 < 10ms。而且完全不增加源站负载。
第 7 章核心知识回顾:
| 概念 | 一句话解释 |
|---|---|
| 边缘计算 | 在 CDN 节点运行代码,不回源站直接处理请求 |
| Cloudflare Workers | V8 Isolates,0 冷启动,最推荐的边缘计算平台 |
| A/B 测试 | 在边缘按规则分流用户,零后端改动 |
| 地理定向 | 根据 request.cf.country 返回不同内容 |
| 适用场景 | 请求改写、鉴权、分流、Header 注入——轻逻辑 |