← 返回首页
🔧

CDN入门:内容分发网络

📂 devops ⏱ 3 min 584 words

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

最佳实践

  1. 分层缓存: 使用多级缓存提高命中率
  2. 缓存预热: 提前缓存热点资源
  3. 版本控制: 静态资源使用版本号或hash
  4. 监控告警: 监控缓存命中率和性能
  5. 刷新策略: 制定缓存刷新和更新策略