图片上传流程

第一版上传:直接存磁盘

“光影”上线第一天,上传接口只有十几行代码:

简单粗暴,图片直接存到 /var/www/photos/。上线第一天我上传了 3 张照片,一切正常。

然后小李来了。

他带着 5 张索尼 A7R5 拍的夜景,每张 8.7 MB。我的 Flask 服务器接收这 5 张图花了 40 秒——因为 Nginx 默认的 client_max_body_size 只有 1MB,我改成了 50MB,但单线程处理大文件依然很慢。

更要命的是,10 个用户同时上传时,服务器的带宽和内存开始告急:

这还没考虑带宽。我的 5Mbps 服务器上行带宽,同时服务上传和下载,直接打满。

第二版上传:流式写入 + 分片

我先优化了上传本身,不把整个文件读入内存:

内存问题缓解了,但带宽问题还在。于是我又加了分片上传支持:

分片解决了大文件上传的问题,但还有一个根本性的问题——所有流量都经过我的服务器。无论怎么优化,上传带宽和存储都是单机的天花板。

第三版上传:客户端直传 OSS

我研究了一圈,发现业界几乎都在用客户端直传对象存储的方案。

核心思路:服务器不碰文件,只负责签发上传凭证。

第一版:客户端 → 我的服务器 → 磁盘
第二版:客户端 → 我的服务器(流式)→ 磁盘
第三版:客户端 → OSS(服务器只签凭证)

前端直传 OSS:

对比三版方案

指标第一版(磁盘中转)第二版(流式分片)第三版(直传 OSS)
服务器带宽消耗上传 + 下载全占上传 + 下载全占几乎为零(只签凭证)
内存占用文件大小 × 并发数极小极小
支持最大文件受内存限制受磁盘限制5TB(OSS 限制)
断点续传✅(OSS 分片)
可扩展性单机天花板单机天花板无限(OSS 弹性)
上传速度受服务器带宽限制受服务器带宽限制OSS 多线 BGP,极速
运维复杂度

直传 OSS 最大的好处:上传流量完全不走我的服务器。OSS 的带宽是海量的,用户上传 100MB 的 RAW 文件也能在几秒内完成。

安全考量

客户端直传 OSS 后,我需要确保几个安全问题:

还有一个关键问题:用户可能伪造上传回调。解决方案是在 OSS 侧配置回调签名验证: