现代网站的性能体验已成为用户留存的关键因素。根据 Google 统计,页面加载时间从 1 秒增加到 3 秒,跳出率会上升 32%。CDN(内容分发网络)与多层缓存体系是提升网站加载速度的核心基础设施。本文将从架构设计到具体配置,完整解析企业级网站 CDN 加速与缓存优化方案。
一、CDN加速的核心原理
CDN 的本质是在全球部署边缘节点,将内容缓存到离用户最近的节点上。当用户请求到达时,CDN 边缘节点直接返回缓存内容,无需回源到源站服务器。CDN 降低延迟的三重机制:
- 物理距离缩短:边缘节点与用户同区域,网络 RTT 从数百毫秒降到十毫秒级
- 网络路径优化:CDN 骨干网直连,绕过公网拥塞节点
- 连接复用:CDN 节点与源站保持长连接,减少 TCP 握手开销
二、CDN缓存层级设计
一个完整的企业级 CDN 加速架构通常包含三层缓存:
用户浏览器缓存
↓ (Miss)
CDN 边缘节点缓存(L1)
↓ (Miss)
CDN 中间源缓存(L2/Parent Cache)
↓ (Miss)
源站 Nginx 本地缓存(Proxy Cache)
↓ (Miss)
应用层缓存(Redis/Memcached)
↓ (Miss)
数据库
1. 浏览器缓存层
通过 HTTP 缓存头控制浏览器缓存行为,是最零成本的加速手段:
# Nginx 静态资源缓存配置
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff2|ttf)$ {
# 强缓存:1年内有效
expires 365d;
add_header Cache-Control "public, immutable";
# immutable 关键字告知浏览器该资源不会变化
# 用户刷新页面时也不会发起条件请求
}
# HTML 文件使用协商缓存
location ~* \.html$ {
add_header Cache-Control "no-cache";
# 每次请求都向服务器验证是否更新
}
对于使用文件指纹(hash)的资源命名方案,可以放心使用强缓存:
<!-- 构建工具生成的带 hash 文件名 -->
<link rel="stylesheet" href="/static/css/main.a1b2c3d4.css">
<script src="/static/js/vendor.e5f6g7h8.js"></script>
<!-- 文件内容变化时 hash 变化,URL 也变化,天然避免缓存过期问题 -->
2. CDN边缘缓存层
CDN 边缘节点缓存是加速效果最显著的一层。配置关键在于合理设置缓存 TTL 和缓存规则。
# 以主流 CDN 为例的缓存规则配置
# 静态资源:强缓存
/静态资源路径(css/js/img) - 缓存 365 天
# 动态接口:不缓存
/api/* - 回源(no-cache)
# HTML 页面:短缓存 + 条件回源
/*.html - 缓存 5 分钟,支持 Last-Modified 验证
# 首页:不缓存或极短缓存
/ - 缓存 30 秒
缓存键(Cache Key)的设计至关重要。默认 CDN 以 URL 作为缓存键,但很多场景需要更精细的控制:
# 忽略特定查询参数
# /api/data?ts=123 和 /api/data?ts=456 共享同一缓存
缓存键规则: $scheme://$host$uri(不含查询参数)
# 设备区分(Mobile/Desktop 分离缓存)
缓存键追加: $http_user_device
# 或基于 UA 判断:如果包含 Mobile 则追加 mobile 标记
# 多语言区分
缓存键追加: $http_accept_language
3. 源站Nginx缓存层
即使用户请求穿透了 CDN 缓存,源站 Nginx 的 proxy_cache 仍能拦截大量回源请求:
# Nginx proxy_cache 配置
http {
proxy_cache_path /var/cache/nginx
levels=1:2
keys_zone=api_cache:100m
max_size=10g
inactive=60m
use_temp_path=off;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_use_stale error timeout updating
http_500 http_502 http_503 http_504;
proxy_cache_background_update on;
proxy_cache_lock on;
proxy_cache_lock_timeout 10s;
}
server {
location /api/ {
proxy_cache api_cache;
proxy_cache_valid 200 10m;
proxy_cache_valid 404 1m;
# 添加缓存命中状态响应头
add_header X-Cache-Status $upstream_cache_status;
# HIT=命中缓存 MISS=未命中 EXPIRED=过期 STALE=使用过期缓存
# UPDATING=正在更新 REVALIDATED=已验证
proxy_pass http://backend;
}
}
proxy_cache_use_stale 配置非常实用——当源站故障时返回过期缓存而非错误页面,保证服务可用性。
三、CDN缓存刷新策略
1. 主动刷新(Purge)
# 通过 CDN API 主动推送刷新请求
curl -X POST https://api.cdn-provider.com/v2/cache/purge \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"urls": [
"https://www.example.com/index.html",
"https://www.example.com/static/css/main.css"
]
}'
# 或按目录刷新(部分CDN支持)
curl -X POST https://api.cdn-provider.com/v2/cache/purge \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"dirs": ["https://www.example.com/news/"]
}'
2. 被动刷新(TTL过期)
适合实时性要求不高的内容。设置较短 TTL(如 5 分钟),等待自然过期。结合 stale-while-revalidate 策略可以在刷新时保持服务:
# HTTP Cache-Control 头
Cache-Control: max-age=300, stale-while-revalidate=600
# 含义:缓存300秒,过期后可在600秒内使用过期缓存并异步刷新
3. 版本化URL(推荐方案)
对于静态资源,使用文件 hash 命名方案,发布新版本时 URL 自然变化,无需刷新缓存:
# v1.0.0
/static/js/app.a1b2c3.js
# v1.0.1(内容变化,hash变化)
/static/js/app.d4e5f6.js
# 旧 URL 文件永久保留在 CDN,新 URL 自动回源拉取
四、动态内容加速
CDN 不仅加速静态资源,也能优化动态 API 的传输效率:
1. 动态加速(DSA)
CDN 利用骨干网优化 TCP 连接路径、使用 HTTP/2 或 HTTP/3 多路复用、TLS 会话复用等技术降低动态请求延迟。
2. 边缘计算(Edge Functions)
// CDN 边缘 Worker 示例:在边缘节点处理鉴权
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const token = request.headers.get('Authorization');
// 边缘验证 Token
if (!token || !await verifyToken(token)) {
return new Response(JSON.stringify({error: 'Unauthorized'}), {
status: 401,
headers: {'Content-Type': 'application/json'}
});
}
// 验证通过,转发到源站
return fetch(request);
}
async function verifyToken(token) {
// 边缘节点缓存的 JWT 验证
// 避免每次请求都回源验证
return true;
}
五、缓存监控与告警
缓存命中率是衡量 CDN 效果的核心指标,建议保持 95% 以上:
# Nginx 日志记录缓存状态并统计
log_format cache_status '$remote_addr - $status '
'$upstream_cache_status "$request"'
' $body_bytes_sent $request_time';
# 使用 goaccess 分析缓存命中率
goaccess /var/log/nginx/access.log --log-format='cache_status' \
-o /var/www/cache-report.html --real-time-html
# Prometheus 监控缓存指标
# nginx_vts_exporter 可采集缓存命中数据
location /status {
vhost_traffic_status_display;
vhost_traffic_status_display_format prometheus;
}
六、安全与防护集成
现代 CDN 集成了丰富的安全防护能力:
# 1. HTTPS 证书托管
# CDN 节点提供 SSL 证书,源站可以仅 HTTP 或自签证书
# 回源加密:CDN 到源站使用 HTTPS
# 2. WAF 防护规则
# 在 CDN 边缘节点拦截 SQL 注入、XSS、CC 攻击
# 基于请求频率、UA、IP 信誉等维度
# 3. 访问控制
# IP 黑白名单
# 地域访问控制(Geo-blocking)
# Token 鉴权(URL 签名防盗链)
# URL 签名示例
# 原始URL: https://cdn.example.com/video/hd.mp4
# 签名URL: https://cdn.example.com/video/hd.mp4?auth_key=1719720000-0-0-a1b2c3d4e5f6
# auth_key 格式:过期时间戳-参数-自定义-签名哈希
七、多CDN调度策略
大型网站通常接入多家 CDN 厂商以实现冗余和最优覆盖。智能 DNS 调度是实现多 CDN 的常见方案:
# 基于 DNS 的多 CDN 调度逻辑
# 1. 根据用户 IP 地理位置选择延迟最低的 CDN
# 2. 根据各 CDN 实时健康状态自动切换
# 3. 按比例灰度分配流量(如 70% CDN-A,30% CDN-B)
# 健康检查脚本伪代码
def get_best_cdn(user_ip):
cdn_scores = {}
for cdn in ["cdn_a", "cdn_b", "cdn_c"]:
# 检查 CDN 健康状态
health = check_cdn_health(cdn)
# 计算 RTT
rtt = measure_rtt(user_ip, cdn)
if health:
cdn_scores[cdn] = rtt
return min(cdn_scores, key=cdn_scores.get)
结语
网站加速是一个分层递进的系统工程:浏览器缓存解决重复访问、CDN 边缘缓存解决地域距离、源站 Nginx 缓存降低回源压力、应用层缓存保护数据库。每一层都有其适用的场景和配置要点。
落地建议:先部署浏览器缓存和 CDN(成本最低、效果最显著),再优化源站 Nginx proxy_cache,最后补充应用层 Redis 缓存。持续监控各层缓存命中率,针对性优化低效环节。配合边缘计算能力,未来越来越多的业务逻辑可以在 CDN 边缘节点直接处理,进一步降低源站压力和用户延迟。