CDN 加速

问题来了

图片存储和处理能力稳定后,用户真正感知到的是访问速度。

我记得第一次收到用户反馈说”图片加载太慢”的时候,第一反应是加服务器带宽。但很快发现,用户分布在全国不同城市,源站在华东,华南和西南的用户延迟天然就高。加带宽解决不了距离问题。

CDN 加速的目标不是简单地把对象存储前面套一层缓存,而是让全国不同网络环境下的用户都能以低延迟、高命中率、可控成本的方式拿到正确图片。

架构演进

最简实现:Flask + 本地磁盘,无 CDN,无压缩
用户层
用户浏览器直接访问服务器
应用层
Flask 服务器1 核 2G,5Mbps 带宽
存储层
本地磁盘100GB,无冗余
客户端直传 OSS + 缩略图生成 + WebP 转换
用户层
用户浏览器直传 OSS
应用层
上传服务签发 STS 凭证
处理服务缩略图 + WebP
存储层
阿里云 OSS原图 + 缩略图
PostgreSQL元数据
CDN 全球加速 + 内容审核 + 异步处理队列
用户层
用户浏览器就近访问 CDN
CDN 层
阿里云 CDN2800+ 节点,边缘裁剪
应用层
上传服务×3签发凭证 + 回调
审核服务×2鉴黄 + OCR
处理服务×4多尺寸 + WebP/AVIF
数据层
阿里云 OSS标准 + 低频 + 归档
RabbitMQ异步处理队列
PostgreSQL元数据 + 用户
生产级图片系统:12,000 用户,85,000 张图片,月成本 ¥1,720
用户层
用户浏览器<picture> + 懒加载
CDN 层
阿里云 CDN缓存命中率 96%,边缘裁剪
服务层
上传服务×3STS 凭证 + 频率限制
审核服务×2鉴黄 + OCR + 人审
处理服务×4多尺寸 + EXIF
数据层
阿里云 OSS标准 + 低频 + 归档
RabbitMQupload→audit→process
辅助系统
PrometheusCDN 命中率 / 延迟
Grafana监控面板 + 告警

到这个阶段,系统从”源站直接对外”演进到”CDN 边缘节点对外,源站只在未命中时回源”。客户端的请求先到达最近的边缘节点,命中则直接返回,未命中才回源到图片处理服务或对象存储。

缓存键设计

图片请求通常包含尺寸、格式、质量、裁剪方式和鉴权参数。如果缓存键设计不稳定,就会造成同一张图片被重复缓存,或者不同版本互相污染。

我踩过的坑是一开始把整个 query string 都放进缓存键,结果用户每次请求带的时间戳不同,导致命中率不到 10%。后来把参数拆开,只把真正影响图片内容的参数纳入缓存键:

缓存键 = 原图路径 + 尺寸 + 格式 + 质量 + 裁剪方式 + 版本号
鉴权参数和时间戳不纳入缓存键,但在边缘节点校验

这样同一张图的 200x200 WebP 版本在全国只有一份缓存,命中率很快升到了 90% 以上。

回源与过期策略

未命中时,CDN 会回源到图片处理服务。处理服务生成派生图后,带着正确的缓存头返回:

Cache-Control: public, max-age=86400, stale-while-revalidate=3600
ETag: "v3-abc123"
Last-Modified: Wed, 21 Aug 2024 10:00:00 GMT

关键设计点:

  • max-age 决定缓存多久,热门图片可以设长一些
  • stale-while-revalidate 允许过期后先返回旧图,同时异步回源更新
  • ETag 用于版本切换时精确刷新缓存

当图片被审核召回或版本更新时,通过 CDN 的刷新接口按 URL 或目录主动清除缓存,而不是等自然过期。

边缘处理

图片 CDN 还承担动态处理和边缘优化的职责:

  • 热门尺寸预生成:对于常见尺寸(头像 100x100、列表图 400x300),可以在上传后异步生成并推到边缘
  • 长尾尺寸按需处理:首次请求时回源处理,结果缓存到边缘
  • 参数空间限制:通过白名单限制允许的尺寸和格式,防止恶意请求制造无限变体
  • WebP/AVIF 自动协商:根据客户端 Accept 头自动返回最优格式

安全防护

CDN 是图片分发的最后一公里,也是安全防护的重要环节:

  • 签名 URL:敏感图片通过带过期时间的签名 URL 访问,防止链接被无限转发
  • 防盗链:通过 Referer 白名单限制图片只能在自有域名下展示
  • 访问日志:记录每张图的访问来源、时间、状态码,用于异常检测和审计
  • 异常回源限流:当某个 URL 回源率异常升高时,自动限流防止源站被打垮

上线后的运营

CDN 不是配好就完事的,需要持续运营:

  • 热门图片预热:大促或热点事件前,提前把热门图片推到所有边缘节点
  • 缓存污染排查:当用户反馈看到旧图时,快速定位是哪个节点的缓存没刷新
  • 版本切换刷新:图片处理策略升级后,按目录批量刷新缓存
  • 跨区域质量监控:监控不同区域的命中率、回源率、边缘延迟和 4xx/5xx 比例

验收标准

完成本章后,你应当能设计一条完整的图片访问路径:

  1. 客户端根据自身能力选择合适格式(WebP/AVIF/JPEG)
  2. CDN 根据稳定缓存键命中边缘资源
  3. 未命中时回源到图片处理服务或对象存储
  4. 结果带着正确的缓存头返回
  5. 通过命中率、回源率、边缘延迟和错误率持续优化

CDN 是图片体验的最后一公里,设计时必须同时考虑速度、正确性、安全和成本。

章节