起点
一张图片,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, ~15KB | 1200px, ~80KB | WebP | ✅ |
| 小红书 | 200px, ~10KB | 800px, ~60KB | WebP/AVIF | ✅ |
| 微博 | 300px, ~20KB | 1000px, ~100KB | WebP | ✅ |
| 淘宝 | 250px, ~8KB | 800px, ~50KB | WebP | ✅ |
共同模式:
- 绝不直接展示原图——列表用缩略图,详情用中等尺寸,原图只在用户主动请求时提供
- 全部用 WebP 或 AVIF——同等质量下比 JPEG 小 30%~50%
- 全部走 CDN——用户就近访问,延迟降到 10ms 级
这三个策略,对应着图片系统的三个核心需求:
缩略图 + 格式转换 → 解决"图片太大"的问题(压缩优化)
多尺寸适配 → 解决"加载太慢"的问题(按需处理)
CDN 分发 → 解决"传输延迟"的问题(就近访问)我的第一个决定:先做缩略图
凌晨 3 点,我做了一个决定:先解决最紧急的问题——图片太大。
方案很简单:用户上传图片后,自动生成多个尺寸的缩略图。
725 倍。一张 8.7 MB 的原图,缩放到 300px 宽并转成 WebP 后,只有 12 KB。
我更新了上传接口:
列表页改用 small 缩略图:
效果立竿见影:
| 指标 | 优化前 | 优化后 | 改善 |
|---|---|---|---|
| 列表页 20 张图总大小 | 174 MB | 240 KB | 缩小 725 倍 |
| 首屏加载时间 | 12 秒 | 0.5 秒 | 快 24 倍 |
| 带宽消耗 | 174 MB/次 | 240 KB/次 | 节省 99.86% |
但这远远不够
缩略图解决了”图片太大”的问题,但还有四个问题没解决:
- CDN:用户还是从我的服务器下载图片,异地用户依然慢
- 存储:每张原图 + 3 个缩略图,磁盘消耗在加速
- 审核:用户上传了什么内容,我一无所知
- 高可用:服务器挂了,所有图片都不可访问
凌晨 4 点,我关上电脑,躺在床上。脑子里浮现出一张图片系统需要解决的问题全貌:
用户上传图片
│
├── 存到哪里? → 存储方案
├── 怎么压缩? → 压缩优化
├── 内容安全吗? → 内容审核
├── 怎么快速分发给用户? → CDN 加速
└── 成本怎么控制? → 成本优化每一个环节都值得深入研究。
我翻了个身,定了个早上 8 点的闹钟。明天开始,我要系统地解决这些问题。
我决定从这个方向开始研究:图片到底是什么?不同的图片格式有什么区别?
只有理解了图片的本质,才能做出正确的技术决策。