CDN 與邊緣快取:加速全球訪問
CDN(Content Delivery Network,內容傳遞網路)是現代 Web 性能優化的基石。本篇將深入探討 CDN 的運作原理與實戰配置。
一、 什麼是 CDN?
1.1 問題:地理延遲
物理距離造成延遲,即使頻寬再大也無法解決。
1.2 解決方案:邊緣節點
1.3 CDN 的價值
| 優勢 | 說明 |
|---|---|
| 降低延遲 | 就近存取 |
| 減少負載 | 分散請求 |
| 高可用性 | 多點部署 |
| DDoS 防護 | 邊緣過濾 |
| 節省成本 | 減少頻寬 |
二、 CDN 運作原理
2.1 首次請求
2.2 後續請求
2.3 快取過期
三、 CDN 快取配置
3.1 遵循 Origin 標頭
CDN 會遵循原始伺服器的 Cache-Control:
javascript
// 原始伺服器
app.use("/assets", (req, res, next) => {
res.set("Cache-Control", "public, max-age=86400, s-maxage=604800");
next();
});
// s-maxage: CDN 快取 7 天
// max-age: 瀏覽器快取 1 天3.2 CDN 規則覆蓋
大多數 CDN 允許設定規則覆蓋:
yaml
# Cloudflare 頁面規則
- url: "*.example.com/assets/*"
settings:
browser_ttl: 86400
edge_ttl: 604800
cache_level: cache_everything3.3 快取 Key
快取以什麼作為識別:
# 預設:URL
https://example.com/api/data
# 可包含:
# - 查詢參數
# - Cookie
# - 標頭
# - 地理位置javascript
// 設定 Vary 影響快取 Key
app.get("/api/content", (req, res) => {
res.set("Vary", "Accept-Language");
// ...
});四、 快取失效(Purge)
4.1 為什麼需要 Purge?
- 內容更新需要立即生效
- 發現錯誤需要緊急修正
- 快取還沒過期但必須更新
4.2 Purge 方式
| 方式 | 說明 | 使用場景 |
|---|---|---|
| 單一 URL | 清除特定檔案 | 個別更新 |
| 前綴 (Prefix) | 清除路徑下所有 | 批量更新 |
| 標籤 (Tag) | 清除相關資源 | 精確控制 |
| 全部 (Purge All) | 清除所有快取 | 緊急情況 |
4.3 API 範例
javascript
// Cloudflare Purge API
async function purgeUrls(urls) {
const response = await fetch(
`https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/purge_cache`,
{
method: "POST",
headers: {
Authorization: `Bearer ${API_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ files: urls }),
}
);
return response.json();
}
// 使用
await purgeUrls([
"https://example.com/image.jpg",
"https://example.com/style.css",
]);4.4 標籤 Purge
javascript
// 設定標籤
app.get("/api/posts/:id", async (req, res) => {
const post = await Post.findById(req.params.id);
res.set("Cache-Tag", `post-${post.id}, author-${post.authorId}`);
res.json(post);
});
// 當作者更新時,清除所有相關文章
async function purgeByAuthor(authorId) {
await cloudflare.purgeByTag([`author-${authorId}`]);
}五、 主流 CDN 比較
5.1 服務商一覽
| CDN | 特點 | 適用場景 |
|---|---|---|
| Cloudflare | 免費方案、DDoS 防護 | 通用 |
| AWS CloudFront | AWS 整合、Lambda@Edge | AWS 生態 |
| Fastly | 即時 Purge、VCL | 高度客製 |
| Akamai | 全球最大網路 | 企業級 |
| Bunny CDN | 價格便宜 | 預算有限 |
5.2 定價模式
| 模式 | 說明 |
|---|---|
| 頻寬計費 | 按傳輸量 |
| 請求計費 | 按請求數 |
| 混合計費 | 兩者結合 |
六、 Cloudflare 配置
6.1 基本設定
bash
# 1. 註冊並添加網站
# 2. 更改 DNS 為 Cloudflare
# 3. 配置快取規則6.2 頁面規則
yaml
# 靜態資源:積極快取
- url: "example.com/assets/*"
settings:
cache_level: cache_everything
edge_ttl: 2592000 # 30 天
browser_ttl: 86400 # 1 天
# API:根據回應標頭
- url: "example.com/api/*"
settings:
cache_level: standard
origin_cache_control: on
# 管理後台:不快取
- url: "admin.example.com/*"
settings:
cache_level: bypass
security_level: high6.3 Workers(邊緣運算)
javascript
// Cloudflare Worker
addEventListener("fetch", (event) => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const url = new URL(request.url);
// 自訂快取邏輯
if (url.pathname.startsWith("/api/")) {
const cacheKey = new Request(url.toString(), request);
const cache = caches.default;
let response = await cache.match(cacheKey);
if (!response) {
response = await fetch(request);
// 只快取成功回應
if (response.ok) {
const cached = response.clone();
cached.headers.set("Cache-Control", "max-age=60");
event.waitUntil(cache.put(cacheKey, cached));
}
}
return response;
}
return fetch(request);
}七、 AWS CloudFront 配置
7.1 建立分發
javascript
// AWS CDK
import * as cloudfront from "aws-cdk-lib/aws-cloudfront";
import * as origins from "aws-cdk-lib/aws-cloudfront-origins";
const distribution = new cloudfront.Distribution(this, "Dist", {
defaultBehavior: {
origin: new origins.S3Origin(bucket),
cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
},
additionalBehaviors: {
"/api/*": {
origin: new origins.HttpOrigin("api.example.com"),
cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED,
},
},
});7.2 失效(Invalidation)
bash
aws cloudfront create-invalidation \
--distribution-id EDFDVBD632BHDS5 \
--paths "/images/*" "/css/*"八、 最佳實踐
8.1 靜態資源策略
1. 使用內容雜湊命名:app.a1b2c3.js
2. 設定長期快取:max-age=1y
3. HTML 不快取或短期快取
4. 使用版本化部署8.2 API 快取策略
javascript
// 公開、變化慢的資料
res.set("Cache-Control", "public, s-maxage=300");
// 私有資料
res.set("Cache-Control", "private, no-store");
// 使用 stale-while-revalidate
res.set("Cache-Control", "public, s-maxage=60, stale-while-revalidate=86400");8.3 監控快取效能
關注的指標:
- 命中率:快取命中次數 / 總請求數
- 回源頻寬:從 Origin 拉取的資料量
- TTFB:首位元組時間
總結
| 概念 | 說明 |
|---|---|
| CDN | 分散式內容傳遞 |
| 邊緣節點 | 靠近用戶的快取伺服器 |
| s-maxage | 共享快取專用 |
| Purge | 主動清除快取 |
| Cache Tag | 精確失效控制 |
| 邊緣運算 | Workers/Lambda@Edge |
> **選擇 CDN 的考量**:
- 節點覆蓋範圍
- Purge 速度
- 定價模式
- 功能豐富度
- 技術支援
進階挑戰
- 設計一個自動化的快取失效系統,當 CMS(Content Management System,內容管理系統)更新內容時自動 Purge。
- 使用 Cloudflare Workers 實作一個 A/B 測試系統。
- 比較不同 CDN 在你的目標地區的效能表現。