分片上传

当文件从几 MB 变成几百 MB,单次上传的失败成本会非常高。用户等了十分钟,最后因为一次网络抖动全部重来,这是文件系统最直观的体验问题。

分片上传的思路是把一个大文件拆成多个小块,每个分片独立上传,失败时只重传失败的部分。

初始化上传任务 -> 上传 chunk 1..N -> 查询已上传分片 -> 合并文件 -> 校验完成

上传流程

分片上传一般分成四步:

  1. 初始化任务:客户端提交文件名、大小、hash、分片大小,服务端返回 upload_id
  2. 上传分片:客户端按序或并发上传分片,服务端记录分片编号、大小、hash 和存储位置。
  3. 查询进度:客户端断线重连后查询哪些分片已经上传。
  4. 完成合并:所有分片到齐后,服务端合并文件并校验整体 hash。

关键数据表可以拆成两张:

作用
upload_task记录上传任务、文件总大小、分片大小、状态和过期时间
upload_part记录每个分片编号、大小、hash、上传状态和存储位置

这样设计后,上传状态变成可查询、可恢复、可清理的数据,而不是散落在临时目录里的文件。

并发与顺序

分片不一定要按顺序上传。客户端可以同时上传 3 到 6 个分片,提高带宽利用率。但并发数不能无限增大,否则会带来三个问题:

  • 客户端占满用户网络,影响页面其他请求。
  • 服务端打开大量连接,吞吐下降。
  • 对象存储或网关触发限流。

工程上通常让客户端根据网络情况动态调整并发数,服务端则通过用户、文件和 IP 维度做限流。

合并策略

如果文件最终存储在本地磁盘,服务端可以按分片编号顺序合并。但如果后续要接对象存储,最好提前适配对象存储的 multipart 能力,让分片直接进入对象存储,由对象存储完成合并。

合并前必须检查:

  • 分片数量是否完整。
  • 每个分片大小是否符合预期。
  • 分片 hash 是否正确。
  • 最终文件 hash 是否和初始化任务一致。

分片上传解决的是大文件传输可靠性,但它也引入了临时数据清理问题。所有未完成任务都要有过期时间,后台定期清理临时分片,避免存储成本悄悄失控。