CDN 优化:这次怎么落地的

这次做 CDN 优化,从选择服务商到深度优化,。

CDN(Content Delivery Network)通过在全球部署边缘节点,将内容缓存到离用户最近的地方。

CDN 原理

基本原理

CDN(Content Delivery Network)通过在全球部署边缘节点,将内容缓存到离用户最近的地方。

graph TB A[用户] --> B[DNS解析] B --> C[CDN边缘节点] C -->|缓存命中| D[返回内容] C -->|缓存未命中| E[回源服务器] E --> C C --> D style A fill:#FFD700 style C fill:#90EE90 style D fill:#FFB6C1

工作流程

  1. 用户访问 CDN 域名
  2. DNS 解析到最近的 CDN 节点
  3. CDN 节点检查缓存
  4. 缓存命中:直接返回
  5. 缓存未命中:回源获取并缓存

CDN 服务商选择

主流服务商

服务商优势劣势适用场景
Cloudflare免费、全球节点多、安全功能强定制化差中小网站
AWS CloudFront与 AWS 集成好价格高AWS 用户
阿里云 CDN国内节点多、价格合理海外节点少国内为主
腾讯云 CDN节点多、价格优惠文档一般国内为主

选择标准

国内为主:阿里云 CDN、腾讯云 CDN

海外为主:Cloudflare、AWS CloudFront

全球部署:Cloudflare + 国内 CDN

Cloudflare 配置

基础配置

# 添加域名
1. 登录 Cloudflare
2. 添加域名 example.com
3. 修改域名 DNS 服务器到 Cloudflare

# 配置 DNS 记录
Type: CNAME
Name: www
Target: example.com
Proxy status: Proxied(橙色云)

缓存规则

# Page Rules
URL Pattern: *example.com/static/*
Settings:
- Cache Level: Cache Everything
- Edge Cache TTL: 1 month
- Browser Cache TTL: 4 hours

URL Pattern: *example.com/api/*
Settings:
- Cache Level: Bypass
- Disable Performance

压缩配置

# Auto Minify
- JavaScript: 启用
- CSS: 启用
- HTML: 启用

# Brotli
- Enable Brotli: 启用

阿里云 CDN 配置

基础配置

# 添加域名
1. 登录阿里云 CDN
2. 添加域名 example.com
3. 配置 CNAME 记录

# 验证配置
dig CNAME www.example.com

缓存配置

# 缓存配置
目录: /static/*
过期时间: 1 个月

目录: /images/*
过期时间: 6 个月

目录: /api/*
过期时间: 不缓存

回源配置

# 回源协议
协议跟随: HTTP

# 回源 HOST
回源 HOST: example.com

# 回源端口
端口: 80

应用层优化

静态资源版本控制

// webpack.config.js
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  output: {
    filename: '[name].[contenthash].js',
    chunkFilename: '[name].[contenthash].chunk.js',
  },
  plugins: [
    new CleanWebpackPlugin(),
  ],
};

资源预加载

<!-- 预加载关键资源 -->
<link rel="preload" href="/static/css/main.css" as="style">
<link rel="preload" href="/static/js/main.js" as="script">
<link rel="preload" href="/fonts/main.woff2" as="font" crossorigin>

<!-- 预连接到 CDN -->
<link rel="preconnect" href="https://cdn.example.com">

图片优化

# 使用 WebP 格式
ffmpeg -i image.png -c:v libwebp -quality 80 image.webp

# 响应式图片
<picture>
  <source srcset="image.webp" type="image/webp">
  <source srcset="image.jpg" type="image/jpeg">
  <img src="image.jpg" alt="Description">
</picture>

字体优化

/* 使用 font-display 优化字体加载 */
@font-face {
  font-family: 'MyFont';
  src: url('/fonts/myfont.woff2') format('woff2');
  font-display: swap;
}

踩过的坑

坑一:缓存未命中

CDN 缓存命中率低,效果不明显。

解决:优化缓存规则,增加缓存时间。

# 配置缓存规则
目录: /*.js
过期时间: 1 个月

目录: /*.css
过期时间: 1 个月

目录: /*.woff2
过期时间: 1

坑二:跨域问题

CDN 资源跨域访问失败。

解决:配置 CORS 头。

// Nginx 配置
location ~* \.(jpg|jpeg|png|gif|webp|css|js|woff2)$ {
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Methods "GET, OPTIONS";
    add_header Access-Control-Max-Age 86400;
}

# 或者 Cloudflare Page Rules
URL Pattern: *example.com/static/*
Settings:
- Add Header: Access-Control-Allow-Origin: *

坑三:HTTPS 配置

CDN HTTPS 配置复杂。

解决:使用 Let’s Encrypt。

# Cloudflare SSL/TLS
SSL/TLS encryption mode: Full (strict)

# 阿里云 CDN
HTTPS 配置: 开启
证书: Let's Encrypt

坑四:回源问题

CDN 回源失败,导致服务不可用。

解决:配置多个源站,实现高可用。

# 多源站配置
源站 1: origin1.example.com
源站 2: origin2.example.com
源站 3: origin3.example.com

权重: 1:1:1

性能监控

监控指标

// 使用 Performance API
function getCDNPerformance() {
  const resources = performance.getEntriesByType('resource');
  
  return resources.map(resource => ({
    name: resource.name,
    duration: resource.duration,
    transferSize: resource.transferSize,
    decodedBodySize: resource.decodedBodySize
  }));
}

// 分析 CDN 资源
function analyzeCDNResources() {
  const resources = getCDNPerformance();
  const cdnResources = resources.filter(r => r.name.includes('cdn.example.com'));
  
  return {
    count: cdnResources.length,
    totalSize: cdnResources.reduce((sum, r) => sum + r.transferSize, 0),
    avgDuration: cdnResources.reduce((sum, r) => sum + r.duration, 0) / cdnResources.length
  };
}

使用 Lighthouse

# 运行 Lighthouse
npx lighthouse https://example.com --view

# 检查 CDN 配置
# 1. 查看静态资源是否使用 CDN
# 2. 查看缓存头是否正确
# 3. 查看压缩是否启用

最佳实践

缓存策略

# 静态资源:长期缓存
目录: /static/*
过期时间: 1
# 图片:长期缓存
目录: /images/*
过期时间: 1
# API:不缓存
目录: /api/*
过期时间: 不缓存

# HTML:短期缓存
目录: /*.html
过期时间: 1 小时

版本控制

// 使用内容哈希
import { version } from './version.json';

const imageUrl = `/images/logo.png?v=${version}`;

// 或者使用文件名哈希
import logo from './logo.png';

const img = new Image();
img.src = logo;  // 自动带上内容哈希

预热 CDN

# 预热 CDN 缓存
for file in static/images/*; do
    curl -X PURGE "https://cdn.example.com/$file"
done

# 或者使用 Cloudflare API
curl -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/purge_cache" \
  -H "Authorization: Bearer ${API_TOKEN}" \
  -H "Content-Type: application/json" \
  --data '{"files":["https://example.com/static/css/main.css"]}'

写在最后

CDN 优化这东西,不只是技术问题,是用户体验问题。

优化了

  • 首屏加载时间
  • 用户体验
  • 流量成本

带来了

  • 运维成本
  • 缓存管理
  • 配置复杂度

优化之前先评估:

  • 用户分布
  • 内容类型
  • 预算
  • 技术能力

不是所有内容都需要 CDN,有时候本地缓存就够用。


这次 CDN 优化花了两周,从选择服务商到深度优化。优化完成后,首屏加载时间从 3 秒降到 1 秒,海外用户体验提升明显。

版权声明: 本文首发于 指尖魔法屋-CDN 优化:这次怎么落地的https://blog.thinkmoon.cn/post/74-cdn-optimization-global-acceleration-practice/) 转载或引用必须申明原指尖魔法屋来源及源地址!