CDN入门:内容分发网络
CDN入门:内容分发网络
什么是CDN
CDN(Content Delivery Network,内容分发网络)是通过在全球部署边缘节点,将内容缓存到离用户最近的位置,从而加速内容分发的网络系统。
CDN工作原理
CDN工作流程:
├── 1. 用户请求访问资源
├── 2. DNS解析到最近的边缘节点
├── 3. 边缘节点检查缓存
│ ├── 命中: 直接返回缓存内容
│ └── 未命中: 回源获取内容
├── 4. 缓存内容到边缘节点
└── 5. 返回内容给用户
CDN配置
Nginx缓存配置
# nginx-cdn.conf
http {
# 定义缓存路径和参数
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;
# 缓存key
proxy_cache_key "$scheme$host$request_uri";
upstream backend {
server 10.0.0.1:8080;
server 10.0.0.2:8080;
}
server {
listen 80;
# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
proxy_pass http://backend;
proxy_cache my_cache;
proxy_cache_valid 200 30d;
proxy_cache_valid 404 1m;
# 添加缓存状态头
add_header X-Cache-Status $upstream_cache_status;
# 缓存锁(防止缓存击穿)
proxy_cache_lock on;
proxy_cache_lock_timeout 5s;
# 过期时间
expires 30d;
add_header Cache-Control "public, immutable";
}
# API不缓存
location /api/ {
proxy_pass http://backend;
proxy_cache off;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
}
}
Varnish配置
# default.vcl
vcl 4.0;
backend default {
.host = "10.0.0.1";
.port = "8080";
.connect_timeout = 5s;
.first_byte_timeout = 60s;
}
sub vcl_recv {
# 设置缓存key
set req.http.X-Hash = req.url;
# 静态资源缓存
if (req.url ~ "\.(jpg|jpeg|png|gif|ico|css|js)$") {
unset req.http.Cookie;
return (hash);
}
# API不缓存
if (req.url ~ "^/api/") {
return (pass);
}
}
sub vcl_backend_response {
# 静态资源缓存30天
if (bereq.url ~ "\.(jpg|jpeg|png|gif|ico|css|js)$") {
set beresp.ttl = 30d;
unset beresp.http.Set-Cookie;
}
# 设置缓存状态头
if (beresp.ttl > 0s) {
set beresp.http.X-Cache = "HIT";
} else {
set beresp.http.X-Cache = "MISS";
}
}
sub vcl_deliver {
# 添加调试头
set resp.http.X-Cache-Hits = obj.hits;
}
云CDN配置
AWS CloudFront
# cloudfront.tf
resource "aws_cloudfront_distribution" "cdn" {
enabled = true
is_ipv6_enabled = true
default_root_object = "index.html"
origin {
domain_name = aws_s3_bucket.assets.bucket_regional_domain_name
origin_id = "S3-assets"
s3_origin_config {
origin_access_identity = aws_cloudfront_origin_access_identity.default.cloudfront_access_identity_path
}
}
origin {
domain_name = "api.example.com"
origin_id = "API"
custom_origin_config {
http_port = 80
https_port = 443
origin_protocol_policy = "https-only"
origin_ssl_protocols = ["TLSv1.2"]
}
}
default_cache_behavior {
allowed_methods = ["GET", "HEAD", "OPTIONS"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "S3-assets"
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
viewer_protocol_policy = "redirect-to-https"
min_ttl = 0
default_ttl = 86400
max_ttl = 31536000
compress = true
}
# API路径不缓存
ordered_cache_behavior {
path_pattern = "/api/*"
allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "API"
forwarded_values {
query_string = true
headers = ["Authorization", "Content-Type"]
cookies {
forward = "all"
}
}
viewer_protocol_policy = "https-only"
min_ttl = 0
default_ttl = 0
max_ttl = 0
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
viewer_certificate {
acm_certificate_arn = aws_acm_certificate.cdn.arn
ssl_support_method = "sni-only"
minimum_protocol_version = "TLSv1.2_2021"
}
aliases = ["cdn.example.com"]
}
阿里云CDN
# alicloud-cdn.tf
resource "alicloud_cdn_domain" "example" {
domain_name = "cdn.example.com"
cdn_type = "download"
scope = "overseas"
sources {
content = "www.example.com"
type = "domain"
port = 80
priority = 20
weight = 10
}
}
resource "alicloud_cdn_domain_config" "cache" {
domain_name = alicloud_cdn_domain.example.domain_name
function_name = "filetype_based_ttl_set"
function_args {
arg_name = "ttl"
arg_value = "2592000"
}
function_args {
arg_name = "file_type"
arg_value = "jpg,png,gif,css,js,woff2"
}
}
缓存策略
缓存头配置
# 缓存策略配置
cache_policies:
static_assets:
pattern: "\\.(jpg|jpeg|png|gif|ico|css|js|woff2)$"
cache_control: "public, max-age=31536000, immutable"
expires: "1y"
html_pages:
pattern: "\\.html$"
cache_control: "no-cache, must-revalidate"
etag: true
api_responses:
pattern: "^/api/"
cache_control: "private, no-cache"
vary: "Authorization"
images:
pattern: "\\.(jpg|jpeg|png|gif|webp)$"
cache_control: "public, max-age=2592000"
content_hash: true
缓存刷新
#!/bin/bash
# cache-refresh.sh
CDN_DOMAIN="cdn.example.com"
# 刷新指定URL
curl -X POST "https://cdn.aliyuncs.com/?Action=RefreshObjectCaches" \
-d "ObjectPath=$CDN_DOMAIN/path/to/file.js" \
-d "ObjectType=File"
# 预热指定URL
curl -X POST "https://cdn.aliyuncs.com/?Action=PushObjectCache" \
-d "ObjectPath=$CDN_DOMAIN/path/to/large-file.zip" \
-d "Area=cn,overseas"
性能监控
Prometheus监控
# cdn-monitoring.yaml
scrape_configs:
- job_name: 'nginx-cache'
static_configs:
- targets: ['nginx-exporter:9113']
- job_name: 'varnish'
static_configs:
- targets: ['varnish-exporter:9131']
groups:
- name: cdn-alerts
rules:
- alert: LowCacheHitRate
expr: nginx_cache_hits / nginx_cache_requests < 0.8
for: 1h
labels:
severity: warning
annotations:
summary: "缓存命中率过低"
description: "缓存命中率低于80%,当前值 {{ $value | humanizePercentage }}"
缓存命中率计算
#!/bin/bash
# cache-stats.sh
# Nginx缓存统计
grep "X-Cache-Status" /var/log/nginx/access.log | \
awk '{print $1}' | sort | uniq -c | sort -rn
# Varnish缓存统计
varnishstat -f MAIN.cache_hit -f MAIN.cache_miss
最佳实践
- 分层缓存: 使用多级缓存提高命中率
- 缓存预热: 提前缓存热点资源
- 版本控制: 静态资源使用版本号或hash
- 监控告警: 监控缓存命中率和性能
- 刷新策略: 制定缓存刷新和更新策略