起点

一张图片,8.7 MB

2024 年 6 月的一个晚上,我上线了我的摄影社区——“光影”。

这是一个很简单的内容平台:摄影师上传作品,其他用户浏览、点赞、收藏。我用了一周时间开发,技术栈也很朴素:

上线第一天,我自己上传了 3 张风景照试了试,感觉不错。

第二天,我的摄影师朋友小李上传了 5 张他用索尼 A7R5 拍的夜景——每张 8.7 MB,分辨率 6000×4000

我点开其中一张,等了 12 秒才看到画面。

“这也太慢了吧?“小李在微信上跟我说,“我在图虫上传同样的照片,秒开。”

我知道问题出在哪里——8.7 MB 的原图,我的 5 Mbps 带宽服务器,传输就要十几秒。但我当时觉得不是什么大问题,用户不多嘛,忍忍就好。

第三天,小李把平台链接分享到了一个 3000 人的摄影群。

3000 人同时看一张 8.7 MB 的图片

那天晚上 8 点,我在吃外卖,手机突然弹出一条告警:

[2024-06-15 20:03:22] ALERT: Server CPU 98%
[2024-06-15 20:03:25] ALERT: Memory usage 89%
[2024-06-15 20:03:28] ALERT: Outbound bandwidth saturated: 5Mbps
[2024-06-15 20:03:31] ALERT: Nginx 502 Bad Gateway

我放下筷子,打开电脑。

一群摄影师,正在同时浏览那些 8.7 MB 的图片。每个人点开一张,服务器就要传输 8.7 MB。3000 人同时点:

11.6 小时。我的服务器需要将近 12 个小时才能把这一波图片传完。

实际上,Nginx 在第 3 分钟就 502 了。

灾后复盘

那天晚上,我在笔记本上写下了问题清单:

问题 1:图片太大
- 原图直出,没有任何压缩
- 一张 8.7 MB 的图片在网页上只需要显示 800px 宽
- 用户在手机上看,甚至只需要 400px

问题 2:没有缩略图
- 列表页直接加载原图
- 20 张图的列表页 = 174 MB
- 用户还没看到内容就跑了

问题 3:没有 CDN
- 所有用户都从我的单台服务器下载
- 北京的服务器,广州的用户延迟 60ms+
- 海外用户更惨,200ms+

问题 4:磁盘在尖叫
- 第一天 3 张图,25 MB
- 第二天 5 张图,43 MB
- 第三天 50 张图,400 MB
- 按这个速度,一个月后磁盘就满了

问题 5:没有内容审核
- 摄影师上传了什么?我不知道
- 如果有人上传违规内容,我是平台方,我要负责

五个问题,每一个都可能让我这个刚上线的平台直接关门。

但说实话,我一点也不沮丧。因为我知道,这些问题本质上都是同一个问题的不同面——如何高效地存储、处理和分发图片。

我开始研究:别人是怎么做的

凌晨 2 点,我打开电脑,开始研究业界方案。

我先看了看图虫——小李说在那里上传照片秒开。我用浏览器开发者工具抓了一下:

# 图虫的图片加载策略

1. 列表页
   - 加载缩略图:300x200, WebP 格式, 约 15 KB
   - 懒加载:滚动到可视区域才加载
   - 20 张图 × 15 KB = 300 KB,秒开

2. 详情页
   - 先加载中等尺寸:1200x800, WebP 格式, 约 80 KB
   - 用户点击"查看原图"时才加载全尺寸:6000x4000, JPEG, 约 5 MB

3. 图片 URL 策略
   - 缩略图:https://cdn.tuchong.com/xxx_w300.webp
   - 中等图:https://cdn.tuchong.com/xxx_w1200.webp
   - 原图:https://cdn.tuchong.com/xxx_original.jpg
   - URL 里直接带处理参数,按需生成

然后我看了看小红书、微博、淘宝——策略都类似:

平台列表缩略图详情页大图格式CDN
图虫300px, ~15KB1200px, ~80KBWebP
小红书200px, ~10KB800px, ~60KBWebP/AVIF
微博300px, ~20KB1000px, ~100KBWebP
淘宝250px, ~8KB800px, ~50KBWebP

共同模式

  1. 绝不直接展示原图——列表用缩略图,详情用中等尺寸,原图只在用户主动请求时提供
  2. 全部用 WebP 或 AVIF——同等质量下比 JPEG 小 30%~50%
  3. 全部走 CDN——用户就近访问,延迟降到 10ms 级

这三个策略,对应着图片系统的三个核心需求:

缩略图 + 格式转换 → 解决"图片太大"的问题(压缩优化)
多尺寸适配       → 解决"加载太慢"的问题(按需处理)
CDN 分发         → 解决"传输延迟"的问题(就近访问)

我的第一个决定:先做缩略图

凌晨 3 点,我做了一个决定:先解决最紧急的问题——图片太大。

方案很简单:用户上传图片后,自动生成多个尺寸的缩略图。

725 倍。一张 8.7 MB 的原图,缩放到 300px 宽并转成 WebP 后,只有 12 KB

我更新了上传接口:

列表页改用 small 缩略图:

效果立竿见影

指标优化前优化后改善
列表页 20 张图总大小174 MB240 KB缩小 725 倍
首屏加载时间12 秒0.5 秒快 24 倍
带宽消耗174 MB/次240 KB/次节省 99.86%

但这远远不够

缩略图解决了”图片太大”的问题,但还有四个问题没解决:

  1. CDN:用户还是从我的服务器下载图片,异地用户依然慢
  2. 存储:每张原图 + 3 个缩略图,磁盘消耗在加速
  3. 审核:用户上传了什么内容,我一无所知
  4. 高可用:服务器挂了,所有图片都不可访问

凌晨 4 点,我关上电脑,躺在床上。脑子里浮现出一张图片系统需要解决的问题全貌:

用户上传图片

    ├── 存到哪里?          → 存储方案
    ├── 怎么压缩?          → 压缩优化
    ├── 内容安全吗?        → 内容审核
    ├── 怎么快速分发给用户? → CDN 加速
    └── 成本怎么控制?      → 成本优化

每一个环节都值得深入研究。

我翻了个身,定了个早上 8 点的闹钟。明天开始,我要系统地解决这些问题。

我决定从这个方向开始研究:图片到底是什么?不同的图片格式有什么区别?

只有理解了图片的本质,才能做出正确的技术决策。