7. 实战案例:从 0 搭建图片加速方案
7.1 业务场景
假设你是一个图片社区的技术负责人,面临以下挑战:
- 用户上传:用户每天上传 100 万张图片(平均 2MB/张)
- 用户访问:每天 5000 万次图片查看请求
- 访问分布:用户遍布全国,海外也有少量访问
- 性能要求:图片加载时间 < 500ms
- 成本预算:尽量控制在每月 5 万以内
7.2 架构设计
┌──────────────────────────────────────┐
│ 用户上传流程 │
└──────────────────────────────────────┘
用户浏览器 后端服务 对象存储
│ │ │
│ 1. 申请上传凭证 │ │
│───────────────────────────────────────────>│ │
│ │ │
│ │ 2. 申请 STS 临时凭证 │
│ │───────────────────────────>│
│ │ │
│ │ 3. 返回 STS 凭证 │
│ │<───────────────────────────│
│ │ │
│ 4. 返回上传凭证(含 STS) │
│<───────────────────────────────────────────│ │
│ │ │
│ 5. 直接上传文件(使用 STS 签名) │
│──────────────────────────────────────────────────────────────────────>│
│ │ │
│ 6. 返回上传结果(URL、ETag 等) │
│<──────────────────────────────────────────────────────────────────────│
│ │ │
│ 7. 通知后端上传完成(保存到数据库) │
│───────────────────────────────────────────>│ │
┌──────────────────────────────────────┐
│ 用户访问流程 │
└──────────────────────────────────────┘
用户浏览器 DNS 解析 CDN 节点 对象存储(源站)
│ │ │ │
│ 1. 请求图片 URL │ │ │
│────────────────────────────────────────>│ │
│ │ │ │
│ │ 2. DNS 查询 │ │
│ │────────────────────>│ │
│ │ │ │
│ │ 3. 返回最优节点 IP │ │
│ │<────────────────────│ │
│ │ │ │
│ 4. 连接 CDN 节点 │ │ │
│────────────────────────────────────────>│ │
│ │ │ │
│ │ 5. 检查缓存 │ │
│ │ ├─ 命中?直接返回 │
│ │ └─ 未命中?继续 │
│ │ │ │
│ │ │ 6. 回源获取 │
│ │ │──────────────────>│
│ │ │ │
│ │ │ 7. 返回文件 │
│ │ │<──────────────────│
│ │ │ │
│ │ 8. 缓存并响应 │ │
│<────────────────────────────────────────│ │7.3 关键配置详解
对象存储配置
存储桶规划:
Bucket: myapp-images-prod
├─ 目录结构:
│ ├─ uploads/ # 用户上传的原图
│ │ ├─ 2024/01/15/user123-abc.jpg
│ │ └─ 2024/01/15/user456-def.png
│ ├─ thumbnails/ # 缩略图
│ │ ├─ small/ # 100x100
│ │ ├─ medium/ # 400x300
│ │ └─ large/ # 800x600
│ └─ processed/ # 处理后的图片(加水印等)
│
├─ 访问权限:
│ ├─ 原图目录:私有(需签名访问)
│ ├─ 缩略图目录:公共读
│ └─ 跨域 CORS:允许 *.myapp.com 访问
│
└─ 生命周期策略:
├─ 上传 7 天后:低频存储(省 40% 费用)
├─ 上传 90 天后:归档存储(省 70% 费用)
└─ 上传 3 年后:自动删除(或转存到更便宜的冷存储)CORS 跨域配置:
xml
<AllowedOrigin>https://myapp.com</AllowedOrigin>
<AllowedOrigin>https://www.myapp.com</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>HEAD</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
<ExposeHeader>ETag</ExposeHeader>
<ExposeHeader>x-oss-request-id</ExposeHeader>
<MaxAgeSeconds>3600</MaxAgeSeconds>CDN 加速配置
缓存策略配置:
全局默认规则:
├─ 缓存键:URL 路径 + 保留 w、h、format 查询参数
├─ 默认 TTL:7 天
└─ 回源 HOST:自动跟随
按文件类型细分:
├─ *.html:
│ ├─ TTL:5 分钟
│ └─ 优先从内存缓存读取
│
├─ *.js, *.css:
│ ├─ TTL:1 年
│ └─ 忽略查询参数(因为文件名有 hash)
│
├─ *.jpg, *.png, *.gif, *.webp:
│ ├─ TTL:30 天
│ ├─ 保留查询参数(w、h、format 用于动态裁剪)
│ └─ 启用图片自动压缩优化
│
└─ /api/*:
├─ TTL:0(不缓存)
└─ 直接回源HTTPS 优化配置:
证书配置:
├─ 证书类型:泛域名证书 *.myapp.com
├─ 部署方式:CDN 控制台上传,自动续期
└─ 备用证书:EV 证书用于主域名(显示绿色地址栏)
TLS 配置:
├─ 最低 TLS 版本:1.2(兼容性与安全平衡)
├─ 最高 TLS 版本:1.3
├─ 密码套件:仅启用强加密套件
├─ OCSP Stapling:开启
├─ TLS 会话复用:开启 Session Ticket
└─ HSTS:开启(max-age=31536000)
HTTP/2 与 HTTP/3:
├─ HTTP/2:开启(多路复用、头部压缩)
├─ HTTP/2 Server Push:按需开启(推荐用 Preload 替代)
└─ HTTP/3 (QUIC):开启(实验性功能,逐步放量)7.4 成本控制策略
费用构成分析
月度 CDN + 对象存储费用构成:
CDN 部分:
├─ 下行流量费(大头,约 60%)
│ ├─ 中国大陆:0.15-0.30 元/GB
│ ├─ 亚太地区:0.40-0.80 元/GB
│ └─ 欧美:0.30-0.60 元/GB
│
├─ 请求数费用(小头,约 5%)
│ ├─ HTTP:0.01-0.05 元/万次
│ └─ HTTPS:0.05-0.15 元/万次(因为 TLS 握手消耗资源)
│
├─ 带宽峰值费用(可选计费方式)
│ └─ 95 峰值计费:适合流量波动大的场景
│
└─ 增值功能费(约 5%)
├─ HTTPS 证书管理
├─ WAF 防护
├─ 实时日志推送
└─ 边缘脚本/函数
对象存储部分:
├─ 存储容量费(约 15%)
│ ├─ 标准存储:0.12-0.15 元/GB/月
│ ├─ 低频存储:0.08-0.10 元/GB/月
│ └─ 归档存储:0.03-0.05 元/GB/月
│
├─ 请求费用(约 5%)
│ ├─ PUT:0.01-0.05 元/万次
│ └─ GET:0.005-0.01 元/万次
│
├─ 数据取回费用(低频/归档)
│ └─ 提前删除或取回收额外费用
│
└─ 回源出流量费(约 10%)
└─ CDN 回源到对象存储的流量费省钱技巧实战
技巧 1:存储分级,自动生命周期管理
yaml
# 生命周期规则示例
rules:
- id: image-lifecycle
prefix: uploads/
transitions:
# 7 天后转低频存储,省 30% 费用
- days: 7
storageClass: IA
# 90 天后转归档存储,省 70% 费用
- days: 90
storageClass: Archive
# 3 年后自动删除
expiration:
days: 1095技巧 2:提高 CDN 命中率,减少回源
命中率从 90% 提升到 95% 意味着什么?
假设:
- 日流量:10 TB
- 命中率 90%:回源 1 TB
- 命中率 95%:回源 0.5 TB
节省回源流量:0.5 TB/天 × 0.15 元/GB × 30 天 = 2250 元/月技巧 3:压缩与格式优化
图片优化方案:
├─ 原图存储在对象存储(不直接对外)
├─ CDN 开启图片处理功能:
│ ├─ 格式自动转换:JPEG → WebP/AVIF(省 30-50%)
│ ├─ 质量自动压缩:视觉无损压缩(省 20-40%)
│ ├─ 尺寸自适应:根据设备返回合适尺寸
│ └─ 渐进式加载:先模糊后清晰
└─ 效果:带宽成本降低 50-70%技巧 4:带宽峰值封顶与告警
yaml
# 带宽封顶配置
bandwidth_cap:
daily_limit: 500 # Mbps,日峰值超过则自动停用 CDN
monthly_limit: 10000 # GB,月流量超过则停用
# 告警阈值
alerts:
- threshold: 70% # 达到 70% 发告警
channels: [sms, email]
- threshold: 90% # 达到 90% 打电话
channels: [phone]