CDN 最初是为静态资源(图片、CSS、JS)设计的缓存网络。但现代 CDN 的价值远不止缓存——它拥有全球部署的边缘节点、优化的骨干网络和接近用户的计算能力。这些基础设施同样可以用于加速动态请求。
动态加速(Dynamic Site Acceleration,DSA)的核心思路是:即使内容不可缓存,也可以通过优化传输路径和传输协议来减少延迟。
一、动态请求为什么慢
在分析加速方案之前,先理解动态请求的延迟构成:
客户端延迟分解(上海用户访问美西源站):
DNS 解析: ~50ms
TCP 握手: ~180ms(1 RTT = 180ms)
TLS 握手: ~360ms(TLS 1.2 需要 2 RTT)
HTTP 请求: ~180ms(1 RTT 发送请求 + 等待响应头)
服务端处理: ~50ms(API 处理时间)
数据传输: ~180ms(1 RTT 传输响应体)
─────────────────────────────────────────
总延迟: ~1000ms
其中网络延迟占比: (1000 - 50) / 1000 = 95%
对比同样的请求经过边缘节点(上海 PoP):
客户端延迟分解(经过上海 PoP 加速):
DNS 解析: ~5ms(Anycast,就近解析)
TCP 握手: ~5ms(到上海 PoP 的 RTT ~5ms)
TLS 握手: ~10ms(TLS 1.3,1 RTT)
HTTP 请求: ~5ms(到 PoP 的 1 RTT)
PoP→源站: ~100ms(优化骨干网 + 持久连接复用)
服务端处理: ~50ms
数据传输: ~5ms(PoP 到客户端)
─────────────────────────────────────────
总延迟: ~180ms
加速比: 1000ms / 180ms ≈ 5.5x
关键优化点:
| 延迟因素 | 直连 | 动态加速 | 优化手段 |
|---|---|---|---|
| DNS 解析 | 50ms | 5ms | Anycast DNS |
| TCP 握手 | 180ms | 5ms | 边缘终止 |
| TLS 握手 | 360ms | 10ms | 边缘终止 + TLS 1.3 |
| 网络传输 | 360ms | 110ms | 智能路由 + 持久连接 |
| 服务端处理 | 50ms | 50ms | 不变(或边缘计算) |
二、TCP 优化
动态加速的第一层是 TCP 协议层面的优化。CDN 在边缘节点和源站之间维护优化的 TCP 连接。
2.1 连接复用(Connection Reuse)
传统模式下,每个用户请求都需要与源站建立新的 TCP 连接。CDN 通过连接池(Connection Pool)复用边缘到源站的长连接:
传统模式(每请求一连接):
用户A ──[TCP+TLS]──→ 源站 4 RTT 建立连接
用户B ──[TCP+TLS]──→ 源站 4 RTT 建立连接
用户C ──[TCP+TLS]──→ 源站 4 RTT 建立连接
CDN 连接复用模式:
用户A ──[TCP+TLS]──→ PoP ──[复用连接]──→ 源站 仅 1 RTT(到 PoP)
用户B ──[TCP+TLS]──→ PoP ──[复用连接]──→ 源站 仅 1 RTT(到 PoP)
用户C ──[TCP+TLS]──→ PoP ──[复用连接]──→ 源站 仅 1 RTT(到 PoP)
Nginx 配置边缘到源站的连接池:
upstream origin_pool {
server origin.example.com:443;
# 每个 worker 进程保持 128 个空闲长连接
keepalive 128;
# 每个连接最多复用 1000 个请求后关闭
keepalive_requests 1000;
# 空闲连接超时 60 秒
keepalive_timeout 60s;
# 每个 worker 最大连接数(包括活跃和空闲)
keepalive_time 1h;
}
server {
listen 443 ssl http2;
location / {
proxy_pass https://origin_pool;
# 必须设置 HTTP/1.1 才能启用 keepalive
proxy_http_version 1.1;
proxy_set_header Connection "";
# 源站连接超时
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
}
}
连接复用的效果量化:
假设条件:
- 每秒 1000 个请求到达同一 PoP
- 源站 RTT = 100ms
- TCP + TLS 握手 = 3 RTT = 300ms
无连接复用:
每秒需要建立 1000 个新连接
握手开销: 1000 × 300ms = 300 秒(连接建立总耗时)
源站 SYN 队列压力大
连接复用(keepalive=128):
稳态下维持 128 个长连接
每个连接每秒处理 ~8 个请求
新连接建立: ~0(稳态下)
节省的握手延迟: 每请求 300ms
2.2 TCP 握手优化
边缘节点可以利用 TCP Fast Open(TFO)和 TLS 1.3 减少握手轮次:
标准 TCP + TLS 1.2(4 RTT):
Client ──── SYN ────────────→ Server
←──── SYN-ACK ────────
──── ACK ─────────────→ TCP 握手完成(1.5 RTT)
──── ClientHello ─────→
←──── ServerHello ─────
←──── Certificate ─────
←──── ServerHelloDone ──
──── ClientKeyExchange →
──── ChangeCipherSpec ──→
──── Finished ─────────→
←──── ChangeCipherSpec ──
←──── Finished ───────── TLS 握手完成(2 RTT)
──── HTTP Request ─────→ 总计 3.5+ RTT
TCP Fast Open + TLS 1.3(1 RTT):
Client ──── SYN + TFO Cookie + ClientHello ──→ Server
←──── SYN-ACK + ServerHello + Finished ──
──── ACK + Finished + HTTP Request ──→ 总计 1 RTT
Linux 内核的 TFO 和 TLS 优化配置:
# 边缘节点内核参数
# 启用 TCP Fast Open(客户端和服务端)
sysctl -w net.ipv4.tcp_fastopen=3
# 增大 TFO 队列
sysctl -w net.ipv4.tcp_fastopen_blackhole_timeout_sec=0
# 启用 TCP 窗口缩放
sysctl -w net.ipv4.tcp_window_scaling=1
# 增大初始拥塞窗口(Google 推荐 10)
ip route change default via $GATEWAY dev eth0 initcwnd 10 initrwnd 10
# 启用 BBR 拥塞控制
sysctl -w net.core.default_qdisc=fq
sysctl -w net.ipv4.tcp_congestion_control=bbr
# 验证
sysctl net.ipv4.tcp_congestion_control
# → bbr2.3 拥塞控制优化
CDN 在不同网段使用不同的拥塞控制算法:
┌──────────┐ 公网(BBR) ┌──────┐ 骨干网(CUBIC) ┌──────────┐
│ 客户端 │ ◄──────────────→ │ PoP │ ◄───────────────→ │ 源站 │
└──────────┘ 高延迟/有丢包 └──────┘ 低延迟/低丢包 └──────────┘
BBR 适合 │ CUBIC 适合
│
连接在此终止
两段独立的 TCP
BBR 在高延迟、有丢包的公网上表现优于 CUBIC:
# 对比测试:跨太平洋链路(RTT=180ms, 丢包率=0.1%)
# CUBIC
$ iperf3 -c origin.us-west.example.com -t 30
[ 5] 0.00-30.00 sec 125 MBytes 34.9 Mbits/sec sender
# BBR
$ sysctl -w net.ipv4.tcp_congestion_control=bbr
$ iperf3 -c origin.us-west.example.com -t 30
[ 5] 0.00-30.00 sec 312 MBytes 87.2 Mbits/sec sender
# BBR 吞吐量是 CUBIC 的 2.5 倍2.4 初始拥塞窗口(initcwnd)优化
TCP 连接建立后,初始拥塞窗口(initcwnd)决定了第一次能发送多少数据。Linux 默认 initcwnd=10(约 14KB),对于小页面可能一次 RTT 就够了,但对于大响应需要多次 RTT:
initcwnd=10(~14KB)传输 100KB 响应:
RTT 1: 发送 14KB (cwnd=10)
RTT 2: 发送 28KB (cwnd=20, 慢启动翻倍)
RTT 3: 发送 56KB (cwnd=40)
RTT 4: 发送 2KB (剩余数据)
总计: 4 RTT
initcwnd=32(~46KB)传输 100KB 响应:
RTT 1: 发送 46KB (cwnd=32)
RTT 2: 发送 54KB (cwnd=64, 慢启动翻倍)
总计: 2 RTT
节省: 2 RTT × 180ms = 360ms
CDN 提供商通常在边缘节点设置较大的 initcwnd:
# 查看当前路由的 initcwnd
ip route show | grep initcwnd
# 设置 initcwnd=32(适用于边缘节点,带宽充裕)
ip route change default via $GATEWAY dev eth0 initcwnd 32 initrwnd 32
# 注意:过大的 initcwnd 在弱网环境可能导致丢包
# 生产环境建议 10-32 的范围三、智能路由
TCP 优化解决的是协议效率问题,智能路由解决的是网络路径问题——公网的 BGP 路由并不总是最优的。
3.1 公网路由的问题
BGP(Border Gateway Protocol)选择路径的标准是最短 AS 路径,而不是最低延迟:
公网 BGP 路径(上海 → 美西):
上海 → 中国电信上海 → 中国电信骨干 → 洛杉矶 IX → US-West DC
延迟: 180ms
经过: 5 个 AS,3 个国际骨干节点
可能存在的问题:
1. 骨干链路拥塞(晚高峰)
2. 国际出口限速
3. 路径次优(绕行)
4. 某段链路丢包率高
用 mtr 观察公网路由质量:
$ mtr -rw -c 100 origin.us-west.example.com
HOST Loss% Snt Last Avg Best Wrst StDev
1. gateway.local 0.0% 100 0.5 0.5 0.4 0.8 0.1
2. 202.97.33.1 (ChinaTelecom) 0.0% 100 5.2 5.1 4.8 6.2 0.3
3. 202.97.90.34 0.0% 100 15.3 14.8 13.9 18.2 1.1
4. 202.97.94.78 (国际出口) 2.0% 100 42.1 45.3 40.2 89.7 12.3 ← 丢包
5. 63.218.0.1 (PCCW 骨干) 2.0% 100 152.3 155.8 148.7 220.1 15.6 ← 抖动大
6. 149.6.34.2 (洛杉矶 IX) 2.0% 100 172.4 175.1 170.3 195.2 5.8
7. 10.0.0.1 (目标DC) 2.0% 100 178.3 180.2 176.1 198.7 4.2
问题:
- 跳 4 国际出口有 2% 丢包
- 跳 5 抖动大(StDev=15.6)
- 整体丢包率累积到 2%3.2 CDN 私有骨干网
大型 CDN 提供商(Cloudflare、Akamai、Google)拥有自己的骨干网络,可以避开公网的拥塞和次优路由:
CDN 私有骨干网路径:
用户(上海) → 上海 PoP → [私有骨干] → 洛杉矶 PoP → 源站
5ms 80ms 5ms
总计: 90ms(vs 公网 180ms)
私有骨干网的优势:
1. 专用光纤,不与公网共享带宽
2. 自主控制路由策略(不依赖 BGP 的 AS 路径选择)
3. 实时监控链路质量,动态切换路径
4. 端到端的 QoS 保障
Cloudflare Argo Smart Routing 的工作原理:
┌──────────────────────────────────────────────────────┐
│ Cloudflare 智能路由系统 │
│ │
│ 实时探测网络: │
│ ┌──────┐ RTT: 3ms ┌──────┐ │
│ │上海PoP│ ──────────────→ │东京PoP│ │
│ │ │ Loss: 0% │ │ │
│ └──────┘ └──────┘ │
│ │ │ │
│ │ RTT: 80ms │ RTT: 60ms │
│ │ Loss: 0.1% │ Loss: 0% │
│ ↓ ↓ │
│ ┌──────┐ RTT: 20ms ┌──────┐ │
│ │洛杉矶 │ ←────────────── │旧金山 │ │
│ │ PoP │ Loss: 0% │ PoP │ │
│ └──────┘ └──────┘ │
│ │
│ 最优路径选择: │
│ 路径A: 上海 → 洛杉矶(直连) 80ms, 0.1% loss │
│ 路径B: 上海 → 东京 → 旧金山 → 洛杉矶 83ms, 0% loss │
│ 选择: 路径B(虽然延迟略高,但零丢包) │
└──────────────────────────────────────────────────────┘
3.3 实时路由质量探测
CDN 的智能路由依赖实时的路径质量探测:
# 路由质量探测的简化模型
import time
import statistics
class PathProbe:
"""每条路径的探测数据"""
def __init__(self, path_id, hops):
self.path_id = path_id
self.hops = hops
self.samples = [] # (timestamp, rtt, loss)
def add_sample(self, rtt_ms, loss_rate):
self.samples.append((time.time(), rtt_ms, loss_rate))
# 保留最近 5 分钟的样本
cutoff = time.time() - 300
self.samples = [(t, r, l) for t, r, l in self.samples if t > cutoff]
def score(self):
"""计算路径综合评分(越低越好)"""
if not self.samples:
return float('inf')
recent_rtts = [r for _, r, _ in self.samples[-30:]]
recent_losses = [l for _, _, l in self.samples[-30:]]
avg_rtt = statistics.mean(recent_rtts)
p99_rtt = sorted(recent_rtts)[int(len(recent_rtts) * 0.99)]
jitter = statistics.stdev(recent_rtts) if len(recent_rtts) > 1 else 0
avg_loss = statistics.mean(recent_losses)
# 综合评分:延迟 + 抖动惩罚 + 丢包惩罚
score = avg_rtt + jitter * 2 + avg_loss * 1000 + (p99_rtt - avg_rtt) * 0.5
return score
class SmartRouter:
"""智能路由选择"""
def __init__(self):
self.paths = {} # path_id -> PathProbe
def select_best_path(self, src, dst):
"""选择 src→dst 的最优路径"""
candidates = [
p for pid, p in self.paths.items()
if pid.startswith(f"{src}-{dst}")
]
if not candidates:
return None
# 按评分排序,选最优
candidates.sort(key=lambda p: p.score())
best = candidates[0]
# 如果最优路径评分变差,考虑切换
if len(candidates) > 1:
second = candidates[1]
# 只有新路径明显更好时才切换(避免频繁抖动)
if second.score() < best.score() * 0.85:
return second
return best3.4 Anycast 与路由收敛
CDN 使用 Anycast 技术让多个 PoP 共享同一个 IP 地址,BGP 自动将流量路由到最近的 PoP:
Anycast 工作原理:
CDN IP: 104.16.1.1(被多个 PoP 同时宣告)
上海电信用户 → BGP 路由 → 上海 PoP(104.16.1.1)
东京用户 → BGP 路由 → 东京 PoP(104.16.1.1)
纽约用户 → BGP 路由 → 纽约 PoP(104.16.1.1)
优势:
- 零配置的就近接入
- 天然的 DDoS 分散能力
- DNS 解析零延迟(IP 不变)
挑战:
- BGP 路由收敛时可能导致连接中断
- 长连接可能被重路由到不同 PoP
- QUIC 的 Connection ID 可以缓解这个问题
四、边缘计算
动态加速的终极形态是将计算逻辑推到边缘——不只是缩短传输路径,而是直接在边缘完成请求处理。
4.1 边缘计算平台对比
┌────────────────────────────────────────────────────────┐
│ 边缘计算平台对比 │
├──────────────┬──────────┬──────────┬───────────────────┤
│ │Cloudflare│ AWS │ Fastly │
│ │Workers │Lambda@Edge│Compute@Edge │
├──────────────┼──────────┼──────────┼───────────────────┤
│ 运行时 │ V8 Isolate│ Node.js │ Wasm + JS │
│ 冷启动 │ 0ms │ 50-500ms │ ~0ms │
│ 执行时间限制 │ 30s (付费)│ 5s │ 60s │
│ 部署节点数 │ 300+ │ 13 Region│ 70+ │
│ 编程语言 │ JS/Wasm │ Node/Py │ JS/Rust/Go/Wasm │
│ 存储 │ KV/R2/D1 │ DynamoDB │ KV Store │
│ WebSocket │ 支持 │ 不支持 │ 支持 │
│ 定价模型 │ 按请求 │ 按请求+时间│ 按请求 │
└──────────────┴──────────┴──────────┴───────────────────┘
4.2 Cloudflare Workers 实战
Workers 使用 V8 Isolate 模型,与传统容器相比冷启动接近零毫秒:
// worker.js — 边缘 API 网关示例
export default {
async fetch(request, env) {
const url = new URL(request.url);
// 1. 边缘认证:在边缘验证 JWT,无效请求直接拒绝
const authResult = await verifyAuth(request, env);
if (!authResult.valid) {
return new Response('Unauthorized', { status: 401 });
}
// 2. 边缘缓存:对特定 API 路径做短时间缓存
if (url.pathname.startsWith('/api/products/')) {
const cacheKey = new Request(url.toString(), request);
const cache = caches.default;
let response = await cache.match(cacheKey);
if (response) {
return response; // 边缘缓存命中,零回源
}
// 回源获取
response = await fetch(request);
// 克隆响应并修改缓存头
const cached = new Response(response.body, response);
cached.headers.set('Cache-Control', 's-maxage=30');
// 异步写入缓存(不阻塞响应)
event.waitUntil(cache.put(cacheKey, cached.clone()));
return cached;
}
// 3. A/B 测试:在边缘决定用户分组
if (url.pathname === '/') {
const bucket = hashUserId(authResult.userId) % 100;
const variant = bucket < 10 ? 'experiment' : 'control';
const originUrl = new URL(request.url);
originUrl.hostname = 'origin.example.com';
const modifiedRequest = new Request(originUrl, {
headers: {
...Object.fromEntries(request.headers),
'X-AB-Variant': variant,
'X-Edge-PoP': request.cf?.colo || 'unknown',
},
});
return fetch(modifiedRequest);
}
// 4. 默认:透传到源站
return fetch(request);
}
};
async function verifyAuth(request, env) {
const token = request.headers.get('Authorization')?.replace('Bearer ', '');
if (!token) return { valid: false };
try {
// 使用 Web Crypto API 验证 JWT
const [header, payload, signature] = token.split('.');
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode(env.JWT_SECRET),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['verify']
);
const valid = await crypto.subtle.verify(
'HMAC',
key,
base64UrlDecode(signature),
new TextEncoder().encode(`${header}.${payload}`)
);
if (valid) {
const claims = JSON.parse(atob(payload));
return { valid: true, userId: claims.sub };
}
} catch (e) {
// 验证失败
}
return { valid: false };
}
function hashUserId(userId) {
let hash = 0;
for (let i = 0; i < userId.length; i++) {
hash = ((hash << 5) - hash + userId.charCodeAt(i)) | 0;
}
return Math.abs(hash);
}
function base64UrlDecode(str) {
str = str.replace(/-/g, '+').replace(/_/g, '/');
const padding = str.length % 4;
if (padding) str += '='.repeat(4 - padding);
return Uint8Array.from(atob(str), c => c.charCodeAt(0));
}4.3 AWS Lambda@Edge 实战
Lambda@Edge 在 CloudFront 的四个事件点运行:
请求流程中的 Lambda@Edge 触发点:
客户端 CloudFront 源站
│ │ │
│── 请求 ──→ │ │
│ ①Viewer Request│ │
│ │── 请求 ──→ │
│ │ ②Origin Request │
│ │ │
│ │ ←── 响应 ── │
│ │ ③Origin Response │
│ ←── 响应 ──│ │
│ ④Viewer Response │
① Viewer Request: 修改请求头、URL 重写、认证检查
② Origin Request: 修改源站请求、添加自定义头
③ Origin Response: 修改源站响应头、添加安全头
④ Viewer Response: 修改最终响应、添加 Cookie
实际的 Lambda@Edge 函数示例:
// Viewer Request — 地理位置路由
exports.handler = async (event) => {
const request = event.Records[0].cf.request;
const headers = request.headers;
// CloudFront 自动注入地理位置信息
const country = headers['cloudfront-viewer-country']?.[0]?.value || 'US';
const city = headers['cloudfront-viewer-city']?.[0]?.value || '';
// 根据地理位置路由到不同源站
const regionMap = {
'CN': 'origin-cn.example.com',
'JP': 'origin-ap.example.com',
'KR': 'origin-ap.example.com',
'US': 'origin-us.example.com',
'DE': 'origin-eu.example.com',
'FR': 'origin-eu.example.com',
};
const originHost = regionMap[country] || 'origin-us.example.com';
// 修改 Host 头指向对应源站
request.headers['host'] = [{ key: 'Host', value: originHost }];
request.origin = {
custom: {
domainName: originHost,
port: 443,
protocol: 'https',
sslProtocols: ['TLSv1.2'],
readTimeout: 30,
keepaliveTimeout: 5,
}
};
// 传递地理位置信息到源站
request.headers['x-viewer-country'] = [{ key: 'X-Viewer-Country', value: country }];
request.headers['x-viewer-city'] = [{ key: 'X-Viewer-City', value: city }];
return request;
};4.4 边缘计算的适用场景
不是所有逻辑都适合放在边缘。判断标准:
适合边缘计算的场景:
┌──────────────────────────────────────────────────────┐
│ ✓ 认证/授权检查(JWT 验证、API Key 校验) │
│ ✓ 请求路由/重写(A/B 测试、地理位置路由、设备适配) │
│ ✓ 响应转换(HTML 注入、图片格式转换、压缩) │
│ ✓ 安全防护(Rate Limiting、Bot 检测、IP 封禁) │
│ ✓ API 聚合(合并多个后端请求,减少客户端往返) │
│ ✓ 个性化(根据 Cookie/地理位置返回不同内容) │
└──────────────────────────────────────────────────────┘
不适合边缘计算的场景:
┌──────────────────────────────────────────────────────┐
│ ✗ 需要访问关系型数据库的复杂查询 │
│ ✗ 长时间运行的后台任务(>30秒) │
│ ✗ 需要大量内存的计算(>128MB) │
│ ✗ 需要持久化状态的有状态服务 │
│ ✗ 涉及事务的业务逻辑 │
└──────────────────────────────────────────────────────┘
4.5 边缘与源站的数据同步
边缘计算最大的挑战之一是数据访问——边缘节点距离中心数据库很远。解决方案:
数据访问模式对比:
1. 边缘 KV 存储(最终一致)
┌────────┐ ┌────────┐ ┌────────┐
│上海 PoP │ │东京 PoP │ │纽约 PoP │
│ KV副本 │ │ KV副本 │ │ KV副本 │
└────┬───┘ └────┬───┘ └────┬───┘
│ │ │
└──────────────┼──────────────┘
│
┌──────┴──────┐
│ 中心 KV 主库 │
└─────────────┘
延迟: 1-5ms(本地读取)
一致性: 最终一致(秒级传播)
适用: 配置、Feature Flag、IP 黑名单
2. 边缘数据库(Cloudflare D1 / Turso)
每个 PoP 有 SQLite 只读副本
延迟: 1-5ms(本地读取),写入需要回中心
适用: 用户配置、产品目录(读多写少)
3. 回源查询(强一致)
边缘 → 私有骨干 → 中心数据库
延迟: 50-200ms
适用: 需要强一致性的数据(账户余额、库存)
Cloudflare Workers KV 的使用示例:
// 使用 Workers KV 做边缘特性开关
export default {
async fetch(request, env) {
// 从边缘 KV 读取 Feature Flag(本地读取,~1ms)
const flags = await env.FEATURE_FLAGS.get('flags', { type: 'json' });
if (!flags) {
return fetch(request); // KV 未初始化,直接回源
}
// 根据 Feature Flag 决定行为
if (flags.maintenance_mode) {
return new Response(
'<h1>系统维护中</h1><p>预计 10 分钟后恢复。</p>',
{ status: 503, headers: { 'Content-Type': 'text/html; charset=utf-8' } }
);
}
// 新版 API 灰度发布
const url = new URL(request.url);
if (url.pathname.startsWith('/api/v2/') && flags.v2_api_percentage > 0) {
const bucket = Math.random() * 100;
if (bucket < flags.v2_api_percentage) {
// 路由到新版 API 服务
url.hostname = 'api-v2.example.com';
return fetch(new Request(url, request));
}
}
return fetch(request);
}
};五、动态加速的架构模式
将以上技术组合,形成完整的动态加速架构:
5.1 全栈加速架构
┌────────────────────────────────────────────────────────┐
│ 动态加速全栈架构 │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ 客户端优化层 │ │
│ │ DNS Prefetch / TCP Preconnect │ │
│ │ H2 Push / 103 Early Hints │ │
│ └──────────────┬───────────────────────┘ │
│ │ │
│ ┌──────────────┴───────────────────────┐ │
│ │ 边缘计算层(PoP) │ │
│ │ 认证 / 路由 / A/B / Rate Limit │ │
│ │ 边缘缓存 / KV 存储 │ │
│ └──────────────┬───────────────────────┘ │
│ │ │
│ ┌──────────────┴───────────────────────┐ │
│ │ 传输优化层 │ │
│ │ TCP 连接复用 / BBR / 智能路由 │ │
│ │ 私有骨干网 / QUIC │ │
│ └──────────────┬───────────────────────┘ │
│ │ │
│ ┌──────────────┴───────────────────────┐ │
│ │ 源站卸载层 │ │
│ │ TLS 终止 / 压缩 / 请求合并 │ │
│ │ DDoS 防护 / WAF │ │
│ └──────────────────────────────────────┘ │
└────────────────────────────────────────────────────────┘
5.2 性能收益量化
完整的动态加速效果对比:
| 优化环节 | 直连延迟 | 加速后延迟 | 节省 | 优化手段 |
|---|---|---|---|---|
| DNS 解析 | 50ms | 5ms | 45ms | Anycast DNS |
| TCP 握手 | 180ms | 5ms | 175ms | 边缘终止 |
| TLS 握手 | 360ms | 10ms | 350ms | 边缘 TLS 1.3 |
| 首字节传输 | 180ms | 100ms | 80ms | 智能路由 + initcwnd |
| 认证检查 | 50ms | 1ms | 49ms | 边缘 JWT 验证 |
| API 处理 | 50ms | 50ms | 0ms | 仍需回源 |
| 响应传输 | 180ms | 5ms | 175ms | 边缘就近返回 |
| 合计 | 1050ms | 176ms | 874ms | 加速 6x |
5.3 动态加速的成本分析
动态加速不是免费的——需要权衡收益和成本:
成本构成:
1. CDN 流量费用
- 静态缓存:0.01-0.08 USD/GB(命中缓存无回源)
- 动态加速:0.08-0.20 USD/GB(每次都回源)
- 动态加速的流量成本是静态缓存的 2-10 倍
2. 边缘计算费用
- Cloudflare Workers: 0.50 USD/百万请求
- Lambda@Edge: 0.60 USD/百万请求 + 执行时间
- 大流量场景成本显著
3. 带宽承诺
- 大多数 CDN 需要最低带宽承诺
- 动态加速通常需要更高的带宽配额
决策矩阵:
场景 | 推荐方案
─────────────────────────────────────────────────
低延迟要求 + 全球用户 | 全栈动态加速(值得投入)
区域性服务(单一市场) | 区域 CDN + 边缘终止
内部服务(B2B) | VPN/专线(不需要 CDN)
预算有限 | 仅静态缓存 + DNS 优化
六、实战:诊断与优化动态请求延迟
6.1 延迟分解方法
系统化分解一个动态请求的延迟:
# 使用 curl 分解 HTTP 请求延迟
curl -o /dev/null -s -w @- https://api.example.com/v1/users/me <<'EOF'
DNS 解析: %{time_namelookup}s\n
TCP 连接: %{time_connect}s\n
TLS 握手: %{time_appconnect}s\n
首字节时间: %{time_starttransfer}s\n
总时间: %{time_total}s\n
下载速度: %{speed_download} bytes/s\n
远程 IP: %{remote_ip}\n
HTTP 状态: %{http_code}\n
EOF
# 输出示例(直连):
DNS 解析: 0.048s
TCP 连接: 0.228s ← RTT ≈ 180ms
TLS 握手: 0.592s ← 2 RTT for TLS 1.2
首字节时间: 0.823s ← 服务端处理 ~50ms + 1 RTT
总时间: 0.891s
下载速度: 15234 bytes/s
远程 IP: 203.0.113.1
HTTP 状态: 200
# 输出示例(经过 CDN 动态加速):
DNS 解析: 0.004s ← Anycast DNS
TCP 连接: 0.009s ← 到边缘 PoP ~5ms
TLS 握手: 0.019s ← TLS 1.3, 1-RTT
首字节时间: 0.152s ← 边缘→源站 + 处理
总时间: 0.158s
下载速度: 92847 bytes/s
远程 IP: 104.16.1.1 ← CDN Anycast IP
HTTP 状态: 2006.2 对比测试脚本
批量测试动态加速效果:
#!/bin/bash
# benchmark-dsa.sh — 动态加速 A/B 对比测试
DIRECT_URL="https://origin.example.com/api/v1/users/me"
CDN_URL="https://api.example.com/api/v1/users/me"
ITERATIONS=100
TOKEN="Bearer eyJ..."
echo "=== Dynamic Site Acceleration Benchmark ==="
echo "Iterations: $ITERATIONS"
echo ""
run_test() {
local label=$1
local url=$2
local total_dns=0 total_connect=0 total_tls=0 total_ttfb=0 total_time=0
local results=()
for i in $(seq 1 $ITERATIONS); do
result=$(curl -o /dev/null -s -w "%{time_namelookup} %{time_connect} %{time_appconnect} %{time_starttransfer} %{time_total}" \
-H "Authorization: $TOKEN" \
"$url")
read dns connect tls ttfb total <<< "$result"
total_dns=$(echo "$total_dns + $dns" | bc)
total_connect=$(echo "$total_connect + $connect" | bc)
total_tls=$(echo "$total_tls + $tls" | bc)
total_ttfb=$(echo "$total_ttfb + $ttfb" | bc)
total_time=$(echo "$total_time + $total" | bc)
results+=("$total")
done
# 计算平均值
avg_dns=$(echo "scale=3; $total_dns / $ITERATIONS * 1000" | bc)
avg_connect=$(echo "scale=3; $total_connect / $ITERATIONS * 1000" | bc)
avg_tls=$(echo "scale=3; $total_tls / $ITERATIONS * 1000" | bc)
avg_ttfb=$(echo "scale=3; $total_ttfb / $ITERATIONS * 1000" | bc)
avg_total=$(echo "scale=3; $total_time / $ITERATIONS * 1000" | bc)
# 计算 P99(排序后取第 99 位)
sorted=($(printf '%s\n' "${results[@]}" | sort -n))
p99_idx=$((ITERATIONS * 99 / 100))
p99=$(echo "scale=3; ${sorted[$p99_idx]} * 1000" | bc)
printf "%-12s DNS: %6sms TCP: %6sms TLS: %6sms TTFB: %6sms Total: %6sms P99: %6sms\n" \
"$label" "$avg_dns" "$avg_connect" "$avg_tls" "$avg_ttfb" "$avg_total" "$p99"
}
echo "Testing direct connection..."
run_test "Direct:" "$DIRECT_URL"
echo "Testing CDN accelerated..."
run_test "CDN:" "$CDN_URL"七、总结
动态加速的三个层次:
- TCP 优化:连接复用、TFO、BBR、initcwnd——在协议层减少握手和传输的 RTT 开销
- 智能路由:私有骨干网、实时路径探测、Anycast——在网络层选择最优传输路径
- 边缘计算:Workers、Lambda@Edge——在计算层将逻辑推到靠近用户的位置
选型建议:
- 如果你的用户分布全球且对延迟敏感(P99 < 200ms),全栈动态加速是必需的
- 如果你的用户主要在一个区域,仅使用边缘 TLS 终止 + 连接复用即可获得大部分收益
- 边缘计算适合无状态的请求处理逻辑(认证、路由、A/B 测试),不适合有状态的业务逻辑
上一篇: CDN 缓存策略:TTL、Purge 与 stale-while-revalidate 下一篇: CDN 与 HTTPS:边缘 TLS、证书管理与安全
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
网络工程索引
汇总本站网络工程系列文章,覆盖分层模型、以太网、IP、TCP、DNS、TLS、HTTP/2/3、CDN、BGP 与故障诊断。
【网络工程】CDN 架构原理:PoP、边缘节点与 Origin Shield
系统解剖 CDN 的多层缓存架构——从 DNS 调度到 PoP 内部结构、Origin Shield 回源保护、多 CDN 部署策略。结合实际配置和响应头分析,给出 CDN 架构的工程理解。
【网络工程】CDN 缓存策略:TTL、Purge 与 stale-while-revalidate
深入剖析 CDN 缓存策略的工程实践——TTL 设置方法论、Purge 机制与一致性保证、stale-while-revalidate 的工程价值、缓存命中率优化与常见缓存问题排查。
【网络工程】CDN 与 HTTPS:边缘 TLS、证书管理与安全
CDN 的 HTTPS 部署涉及边缘 TLS 终止、证书托管、回源加密等多个工程环节。本文系统拆解 CDN HTTPS 的架构模式、证书管理方案、安全最佳实践与常见故障排查方法。