前置阅读:建议先阅读 Cloudflare R2 对象存储实战。
关键概念:R2 的核心差异化优势是零出口费(Zero Egress),这意味着将数据从 R2 分发到全球的成本远低于 AWS S3。对于高流量分发场景,成本节省可达 80%+。
² 跨区域复制与一致性
R2 的多区域复制不是原生功能,需通过 Workers + Rules 实现:
// workers/r2-replication.ts export interface Env { R2_PRIMARY: R2Bucket; // 主区域 bucket R2_BACKUP: R2Bucket; // 备份区域 bucket REPLICATION_QUEUE: Queue; } export default { // 监听 PUT 事件(通过 R2 Event Notifications 或 Object Lifecycle Rules) async fetch(request: Request, env: Env) { const url = new URL(request.url); if (url.pathname === "/replicate") { const { bucket, key } = await request.json(); // 跨区域复制 const source = await env.R2_PRIMARY.get(key); if (!source) return new Response("Not found", { status: 404 }); await env.R2_BACKUP.put(key, source.body, { httpMetadata: source.httpMetadata, customMetadata: { ...source.customMetadata, replicated_at: new Date().toISOString(), source_bucket: bucket, }, }); return Response.json({ replicated: true, key }); } return new Response("OK"); }, // Queue Consumer:异步批量复制 async queue(batch: MessageBatch<any>, env: Env) { for (const message of batch.messages) { const { key } = message.body; const source = await env.R2_PRIMARY.get(key); if (source) { await env.R2_BACKUP.put(key, source.body, { httpMetadata: source.httpMetadata, }); } message.ack(); } }, };复制一致性模型:
策略 延迟 一致性 适用场景 同步复制 +200-500ms 强一致 金融交易记录 异步 Queue ~1-5s 最终一致 常规文件、日志 定时批处理 ~1h 最终一致 冷备份、归档 ³ 对象生命周期管理
R2 原生支持生命周期规则(S3 兼容 API):
# 通过 wrangler 配置生命周期(当前需通过 S3 API 或 Dashboard) # 规则示例:30天后转低频,90天后删除// workers/lifecycle-manager.ts // 自定义生命周期:基于 Workers 定时触发(Cron Triggers) export default { async scheduled(event: ScheduledEvent, env: Env) { // 每天执行一次清理 const { objects } = await env.R2_BUCKET.list({ prefix: "uploads/temp/", }); const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1000; // 7 天前 const toDelete = []; for (const obj of objects) { const uploaded = new Date(obj.uploaded).getTime(); if (uploaded < cutoff) { toDelete.push(obj.key); } } // 批量删除(R2 支持一次最多 1000 个) if (toDelete.length > 0) { // 由于 R2 目前不原生支持批量删除 API,循环删除: await Promise.all( toDelete.map(key => env.R2_BUCKET.delete(key)) ); console.log(`Deleted ${toDelete.length} expired objects`); } }, };# wrangler.toml [triggers] crons = ["0 2 * * *"] # 每天凌晨 2 点⁴ Workers 流式上传与大文件处理
// workers/stream-upload.ts export default { async fetch(request: Request, env: Env) { if (request.method !== "POST") { return new Response("Method not allowed", { status: 405 }); } const url = new URL(request.url); const key = url.searchParams.get("key"); if (!key) return new Response("Missing key", { status: 400 }); // 直接流式转发(不加载到内存) // 适合大文件:视频、备份、日志 await env.R2_BUCKET.put(key, request.body, { httpMetadata: { contentType: request.headers.get("content-type") || "application/octet-stream", }, }); return Response.json({ uploaded: true, key }); }, };分片上传(Multipart Upload):
// workers/multipart-upload.ts // R2 支持 S3 兼容的分片上传 import { S3Client, CreateMultipartUploadCommand, UploadPartCommand, CompleteMultipartUploadCommand } from "@aws-sdk/client-s3"; import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; const s3 = new S3Client({ region: "auto", endpoint: `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`, credentials: { accessKeyId: env.R2_ACCESS_KEY_ID, secretAccessKey: env.R2_SECRET_ACCESS_KEY, }, }); // 步骤 1: 初始化分片上传 export async function initiateMultipart(key: string) { const command = new CreateMultipartUploadCommand({ Bucket: "my-bucket", Key: key, }); const response = await s3.send(command); return response.UploadId; } // 步骤 2: 为每个分片生成预签名 URL(客户端直传) export async function getPresignedPartUrls( key: string, uploadId: string, totalParts: number ) { const urls = []; for (let i = 1; i <= totalParts; i++) { const command = new UploadPartCommand({ Bucket: "my-bucket", Key: key, UploadId: uploadId, PartNumber: i, }); const url = await getSignedUrl(s3, command, { expiresIn: 3600 }); urls.push({ partNumber: i, url }); } return urls; } // 步骤 3: 完成上传 export async function completeMultipart( key: string, uploadId: string, parts: { PartNumber: number; ETag: string }[] ) { const command = new CompleteMultipartUploadCommand({ Bucket: "my-bucket", Key: key, UploadId: uploadId, MultipartUpload: { Parts: parts }, }); return s3.send(command); }⁵ 图片/视频动态优化管道
使用 Cloudflare Image Resizing + Workers 构建动态图片服务:
// workers/image-optimization.ts export default { async fetch(request: Request, env: Env) { const url = new URL(request.url); const key = url.pathname.slice(1); // 去掉前导 / const width = parseInt(url.searchParams.get("w") || "0"); const format = url.searchParams.get("f") || "auto"; const quality = parseInt(url.searchParams.get("q") || "85"); // 检查缓存(KV 中存储已处理的变体) const cacheKey = `img:${key}:w=${width}:f=${format}:q=${quality}`; const cached = await env.CACHE.get(cacheKey, { type: "stream" }); if (cached) { return new Response(cached, { headers: { "Content-Type": `image/${format === "auto" ? "webp" : format}` }, }); } // 获取原始图片 const original = await env.R2_BUCKET.get(key); if (!original) return new Response("Not found", { status: 404 }); // 使用 Cloudflare Image Resizing(需开通 Image Resizing 服务) // 或者使用 Workers 集成 sharp/wasm(实验性) const imageUrl = new URL( `https://imagedelivery.net/${env.IMAGE_ACCOUNT_HASH}/${key}/public` ); if (width) imageUrl.searchParams.set("width", width.toString()); if (format !== "auto") imageUrl.searchParams.set("format", format); imageUrl.searchParams.set("quality", quality.toString()); const optimized = await fetch(imageUrl); // 缓存处理结果(24小时) const body = await optimized.arrayBuffer(); await env.CACHE.put(cacheKey, body, { expirationTtl: 86400 }); return new Response(body, { headers: { "Content-Type": optimized.headers.get("Content-Type") || "image/webp", "Cache-Control": "public, max-age=86400", }, }); }, };图片处理参数速查:
参数 说明 示例 w/width最大宽度 ?w=800h/height最大高度 ?h=600f/format输出格式 ?f=webp/?f=avifq/quality质量(1-100) ?q=85fit适应模式 ?fit=crop/?fit=contain⁶ 成本模型对比
月度假设:存储 5TB,月出口流量 20TB,1000 万次请求
服务商 存储费 出口费 请求费 月总计 vs R2 Cloudflare R2 $0 $0 ~$4 ~$4 基准 AWS S3 Standard $115 $1,800 $50 $1,965 490x AWS S3 + CloudFront $115 $1,200 $85 $1,400 350x Google Cloud Storage $104 $1,600 $40 $1,744 435x MinIO (自托管) $200 (VPS) 含在带宽 - $200 50x 注意:R2 的 “免费” 有使用上限。Pro 以上套餐含更大额度,超额后请求费 $0.36/百万。
⁷ 多云容灾架构
┌─────────────┐ 写 ┌─────────────┐ │ 应用服务器 │──────────→│ R2 (主) │ │ (Workers) │ │ 零出口费分发 │ └─────────────┘ └──────┬──────┘ │ │ │ 异步复制 (Queue) │ 读取 ▼ ▼ ┌─────────────┐ ┌─────────────┐ │ S3 (备份) │ │ 全球 CDN │ │ 合规/冷备 │ │ <50ms 延迟 │ └─────────────┘ └─────────────┘容灾切换逻辑:
class MultiCloudStorage { constructor( private primary: R2Bucket, private backup: S3Client, private healthCheck: () => Promise<boolean> ) {} async get(key: string) { try { if (await this.healthCheck()) { return await this.primary.get(key); } } catch (e) { console.warn("Primary failed, falling back to S3"); } // 灾备读取 return this.backup.send(new GetObjectCommand({ Bucket: "backup", Key: key })); } }
延伸阅读:
- Cloudflare R2 对象存储实战 — 基础接入、S3 SDK、成本测算
- Cloudflare Workers AI 高级实战 — Workers 流式响应优化
- Vercel 与 Cloudflare Pages 对比 — 静态托管方案选型
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。
「工具与平台」更多文章
Vercel Edge Config 完全指南:毫秒级配置下发与 A/B 测试驱动
深入 Vercel Edge Config 全局键值存储:与 Edge Functions / Middleware 的低延迟集成、A/B 测试与功能开关实现、多环境管理、版本控制与回滚策略,提供 TypeScript 端到端实现与性能基准。
Vercel Analytics 深度指南:Web Vitals 监控、真实用户性能与转化归因
全面解析 Vercel Analytics(真实用户监控 RUM)与 Speed Insights(Web Vitals)两大工具,覆盖安装集成、自定义事件追踪、性能瓶颈诊断、转化归因分析,以及与 Google Analytics 4 / Datadog 的对比选型。
Vercel AI SDK 深度实战:Tool Calling、Schema 流式输出与多模型路由
深入 Vercel AI SDK 三大核心包(ai / @ai-sdk/openai / @ai-sdk/react),覆盖 generateObject 结构化输出、streamText 工具调用流、多模型路由与回退、Server Action 集成等高级场景,提供端到端 TypeScript 实现。