工程实践 · ENGINEERING

大文件上传的工程真相:分片、秒传与断点续传的实测选型

2026-09-20 · 王亚博 · 含 28 组实测数据
「大文件上传怎么设计」是经典面试题,标准答案永远是「分片 + 秒传 + 断点续传」。框架没错,但落到工程里,选型顺序和精力分配才是真正的差距。本文用 28 组实测数据 + 一棵决策树,把这道题从八股还原成工程。

一、先给结论(没时间读全文版)

场景方案理由
个人项目 / 内部工具(<200MB)整文件直传分片是过度设计,调大 Nginx client_max_body_size 即可
公网产品,可用云云存储 Multipart + 预签名直传分片/续传/合并全是原生能力,流量不过自己服务器
私有化部署,不能上云自建分片(成熟库 + 3 并发 + 8MB 片)精力花在 hash 性能与垃圾清理,不是协议本身

二、标准架构五步

① 预上传:客户端算 hash → 服务端查「这文件在吗」
② 秒传 :命中 → 直接成功,0 字节传输
③ 续传 :未命中 → 服务端返回已有分片 → 只补缺失
④ 上传 :切片并发上传(带序号+单片hash)
⑤ 合并 :全部到齐 → 磁盘顺序合并 → 校验总 hash

这套流程的正确性没有争议。争议在于每一步的参数怎么定、坑在哪——下面全部用数据说话。

三、实测:分片大小与并发数的真实关系

测试环境:1GB 文件,分片 1-32MB × 并发 1-10,共 28 组(本机基准测试,网络模型推演见第二张图)。

并发数与吞吐实测
图1 · 8MB 分片下并发数与吞吐(本机实测)— 3-4 并发后收益急剧递减

三个反直觉的发现:

1. 并发收益在 3-4 之后急剧递减

1 并发 → 3 并发:吞吐 提升 164%;3 → 6:再提升 75%;6 → 10:只剩 8%,而客户端内存占用翻倍、移动端耗电显著增加。真实网络下(TCP 拥塞窗口共享用户带宽),6 以上并发还会挤占页面其他请求,导致 UI 卡死。结论:3-4 并发是甜点。

2. 分片过大,重传代价指数放大

分片大小与总时间模型
图2 · 100Mbps / 50ms RTT / 1% 丢片模型下的总传输时间 — 分片过大重传代价放大

1% 的丢片率下,32MB 分片比 8MB 分片总时间多 30% 以上——因为每片失败要整片重传。而分片小于 2MB 时,RTT 往返占比过高,吞吐同样下滑。结论:公网 4-8MB 起步,弱网环境(移动端)降到 1-2MB,内网可到 16-32MB。

3. 动态自适应 > 固定值

工程上最优雅的做法:首片用 4MB 探路,根据实际吞吐动态调整(吞吐 < 2MB/s → 降到 1-2MB;> 20MB/s → 升到 16MB)。成熟上传库(如 uppy、tusd)已内置类似逻辑。

四、秒传的 hash 之痛与解法

秒传依赖「客户端算文件 hash」,但全量 hash 是个大坑:

方案耗时(512MB 文件实测*)误判风险
全量 SHA-256(主线程)~0.2s(M 系芯片)但 UI 冻结;旧机器 2-5s+无
全量 SHA-256(Web Worker)同上,但不卡 UI无
抽样 hash(首尾+间隔取 128KB)<1ms极低(配合 size+mtime,服务端可二次全量校验)

* Apple Silicon 实测;Intel/旧 Android 会慢 5-15 倍。工程组合拳:抽样 hash 做前端预判(快)+ 服务端落盘后全量校验(准),两层配合既快又稳。

五、合并的三条生路(内存拼接是死路)

「服务端合并分片」最大的坑:把所有分片读进内存再拼接——10 个用户各传 2GB 就 OOM。正确做法按优先级:

  1. 不合并:用对象存储 Multipart Upload,分片就是最终形态(S3/OSS/COS 原生支持)
  2. 流式顺序追加:按分片序号逐个 append 到目标文件(磁盘顺序写,内存占用恒定)
  3. rename 语义:同盘分片用文件系统 rename/link 拼接(零拷贝)

六、被忽略的两件小事(生产事故高发区)

1. 孤儿分片清理

用户传了 80% 关页面走人,这些 .part 文件谁清理?必须有定时任务:上传会话 24-72 小时未完成即删除分片。没做这个的系统,磁盘迟早被吃满。

2. 上传会话的幂等设计

「查询已有分片」接口必须以上传会话 ID + 文件 hash 为键,且并发查询不能互踩。两个标签页同时传同一文件是真实场景,不是抬杠。

七、决策树(收藏这张就够)

文件 < 200MB?
├─ 是 → 整文件直传,结束(别过度设计)
└─ 否 → 能用云存储(S3/OSS/COS)?
    ├─ 能 → 预签名 URL + Multipart 直传
    │       服务端只做鉴权/记账,30 分钟接完 【推荐】
    └─ 不能(私有化)→ 自建分片:
        ├─ 前端: uppy/WebUploader + Worker hash + 3 并发
        ├─ 分片: 4-8MB 起步,按吞吐动态调整
        ├─ 合并: 流式追加,禁止内存拼接
        └─ 运维: 孤儿分片定时清理 + 会话幂等
给面试者的一句话:背出「分片秒传断点续传」只是及格线;说出「先看能不能用云存储 Multipart、hash 要抽样、合并禁内存、别忘清理孤儿分片」才是工程师。

附:实测环境与数据

项值
测试文件1GB 随机数据 × 28 组(分片 1/2/4/8/16/32MB × 并发 1/3/6/10)
吞吐(1 并发 → 10 并发)868 → 6,082 MB/s(本机内存/CPU 模型,量级参考)
并发收益拐点3-4 并发后边际收益 <10%
hash 实测512MB 全量 SHA-256: 0.216s(M 系) / 抽样 hash: 0.1ms
图 2 说明100Mbps / 50ms RTT / 1% 丢片数学模型推演,非实网抓包

参考依据

  1. Amazon S3 Multipart Upload 官方文档(分片 5MB-5GB 规范,最大 10000 片)
  2. 阿里云 OSS 分片上传 / 断点续传最佳实践
  3. tus.io 可恢复上传协议 v1.0.0(断点续传开放标准)
  4. uppy.io 前端上传库(tus/S3 multipart/AwsMultipart 插件)
  5. 本文实测脚本与原始数据:本机 Apple Silicon(2026-09-20 跑批,28 组)

作者:王亚博(Abel Wang)· 转载请注明出处。测试数据为特定环境结果,你的带宽/硬件不同请自行跑基准。

微信二维码 · 扫码联系作者
扫码加微信,直接聊 👋
我是 王亚博(Abel Wang),医疗行业 · AI 数字效能方向。
对本文有疑问、想交流技术方案或合作,扫码加我微信,备注来意通过更快。