CDN 原理与实践
问题
CDN 是什么?它是如何加速网站访问的?
答案
CDN(Content Delivery Network,内容分发网络)是一组分布在全球各地的服务器,通过就近访问提高内容传输速度。
CDN 工作原理
核心优势
| 优势 | 说明 |
|---|---|
| 降低延迟 | 就近访问边缘节点 |
| 减轻源站压力 | 边缘节点缓存内容 |
| 提高可用性 | 多节点冗余 |
| 抵御攻击 | DDoS 防护 |
| 节省带宽 | 减少跨网流量 |
CDN 访问流程
DNS 智能解析
# 查看 CDN DNS 解析过程
dig www.taobao.com
# 可能看到多级 CNAME
; www.taobao.com. CNAME www.taobao.com.danuoyi.tbcache.com.
; www.taobao.com.danuoyi.tbcache.com. CNAME ...
# 最终返回离用户最近的边缘节点 IP
CDN 缓存策略
缓存控制
// 源站设置缓存头
// Cache-Control: max-age=86400 (缓存 1 天)
// Cache-Control: no-cache (每次验证)
// Cache-Control: no-store (不缓存)
// CDN 常见策略
interface CDNConfig {
// 缓存时间
cacheTTL: {
html: 0, // 不缓存
css: 86400, // 1 天
js: 86400, // 1 天
image: 2592000, // 30 天
font: 31536000 // 1 年
};
// 缓存键
cacheKey: 'url + query + header';
// 忽略查询参数
ignoreQueryString: false;
}
缓存命中与回源
| 场景 | 行为 |
|---|---|
| 缓存命中 | 直接返回,响应快 |
| 缓存未命中 | 回源获取,然后缓存 |
| 缓存过期 | 协商缓存或重新获取 |
| 主动刷新 | CDN 控制台刷新缓存 |
// 判断是否命中 CDN 缓存
// 通常 CDN 会在响应头中标识
// 阿里云 CDN
// X-Cache: HIT TCP_MEM_HIT (命中内存缓存)
// X-Cache: HIT TCP_DISK_HIT (命中磁盘缓存)
// X-Cache: MISS (未命中)
// Cloudflare
// cf-cache-status: HIT
// cf-cache-status: MISS
CDN 配置实践
资源部署
// 1. 静态资源使用 CDN 域名
const assetURL = 'https://cdn.example.com/assets/app.js';
// 2. HTML 保留源站(动态内容)
// https://www.example.com/index.html
// 3. 版本化资源路径(利于缓存)
// ✅ /assets/app.abc123.js
// ❌ /assets/app.js?v=123
Webpack 配置
// webpack.config.js
module.exports = {
output: {
// 使用 contenthash 生成文件名
filename: '[name].[contenthash].js',
// 配置 CDN 域名
publicPath: 'https://cdn.example.com/'
}
};
Vite 配置
// vite.config.ts
export default defineConfig({
base: 'https://cdn.example.com/',
build: {
rollupOptions: {
output: {
// 资源文件名包含 hash
assetFileNames: 'assets/[name].[hash][extname]',
chunkFileNames: 'assets/[name].[hash].js',
entryFileNames: 'assets/[name].[hash].js'
}
}
}
});
CDN 高级特性
1. 边缘计算
// Cloudflare Workers 示例
// 在边缘节点执行代码
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request: Request): Promise<Response> {
const url = new URL(request.url);
// A/B 测试
const variant = Math.random() < 0.5 ? 'a' : 'b';
url.pathname = `/variants/${variant}${url.pathname}`;
// 地理位置定向
const country = request.cf?.country || 'US';
// 请求改写
return fetch(url.toString(), {
headers: {
'X-Country': country
}
});
}
2. 图片优化
// CDN 图片处理
// 原始: https://cdn.example.com/image.jpg
// 缩放
// https://cdn.example.com/image.jpg?w=200&h=200
// 格式转换(自动 WebP)
// https://cdn.example.com/image.jpg?format=webp
// 质量压缩
// https://cdn.example.com/image.jpg?quality=80
// 裁剪
// https://cdn.example.com/image.jpg?crop=center
3. 安全防护
// 防盗链
// Referer 白名单
// 签名 URL(带时间戳和签名)
// 生成签名 URL
function generateSignedURL(
baseURL: string,
secretKey: string,
expireTime: number
): string {
const expire = Math.floor(Date.now() / 1000) + expireTime;
const stringToSign = `${baseURL}${expire}${secretKey}`;
const signature = md5(stringToSign);
return `${baseURL}?expire=${expire}&sign=${signature}`;
}
4. HTTPS 与 HTTP/2
// CDN 通常支持
// - 免费 HTTPS 证书
// - HTTP/2 自动启用
// - HTTP/3 (QUIC)
// - TLS 1.3
CDN 选型对比
| 服务商 | 特点 | 适用场景 |
|---|---|---|
| 阿里云 CDN | 国内节点多,DCDN | 国内业务 |
| 腾讯云 CDN | 与腾讯生态集成 | 国内业务 |
| Cloudflare | 免费套餐,边缘计算 | 全球业务 |
| AWS CloudFront | 与 AWS 集成 | AWS 用户 |
| Fastly | 边缘计算强 | 性能要求高 |
常见面试问题
Q1: CDN 的工作原理?
答案:
- DNS 解析:域名 CNAME 到 CDN,智能 DNS 返回最近节点
- 就近访问:用户访问离自己最近的边缘节点
- 缓存命中:边缘节点有缓存直接返回
- 回源:无缓存时向源站获取,缓存后返回
Q2: CDN 如何选择最优节点?
答案:
CDN 通过智能 DNS 实现节点选择:
| 因素 | 说明 |
|---|---|
| 地理位置 | 根据用户 IP 判断位置 |
| 网络拓扑 | 考虑 ISP、网络跳数 |
| 节点负载 | 避免热点节点 |
| 健康状态 | 剔除故障节点 |
| 实时性能 | RTT、丢包率 |
Q3: CDN 缓存没有生效怎么排查?
答案:
// 1. 检查响应头
// X-Cache: MISS 表示未命中
// 查看 Cache-Control、ETag 等
// 2. 检查缓存规则
// CDN 控制台配置是否正确
// 文件类型是否在缓存列表
// 3. 检查源站响应
// 源站是否设置了 no-cache、no-store
// 是否有 Set-Cookie(默认不缓存)
// 4. 缓存键冲突
// 查询参数不同导致缓存键不同
// 配置忽略查询参数或指定缓存键
// 5. 刷新缓存
// 手动刷新 CDN 缓存
Q4: CDN 和反向代理的区别?
答案:
| 特性 | CDN | 反向代理 |
|---|---|---|
| 节点数量 | 全球分布,大量节点 | 少量服务器 |
| 主要目的 | 加速访问、减轻源站压力 | 负载均衡、安全 |
| 缓存策略 | 边缘缓存,智能分发 | 简单缓存 |
| 使用场景 | 静态资源加速 | API 代理、入口网关 |
Q5: 如何设计一个静态资源缓存策略?
答案:
// 1. HTML: 不缓存或短缓存
// Cache-Control: no-cache
// 每次请求验证,保证最新
// 2. 带 hash 的资源: 长期缓存
// app.abc123.js
// Cache-Control: max-age=31536000, immutable
// 文件名变化即更新
// 3. 图片/字体: 长期缓存
// Cache-Control: max-age=31536000
// 配合 ETag 协商
// 4. API 响应: 不缓存
// Cache-Control: no-store