后端状态管理与分块合并

后端大文件上传的接口设计、uploadId 状态管理、chunk 存储与合并

#type / concept #status / evergreen #tech / dev / backend

[!info] related notes

后端状态管理与分块合并

一句话定义

后端通过 uploadId 标识上传任务,用状态表记录每个 chunk 的上传情况,最后按顺序合并并校验完整性。

核心内容

接口设计

典型接口拆分:

接口作用
POST /upload/init创建上传任务,判断秒传,返回配置
POST /upload/chunk接收一个 chunk,写入存储,更新状态
GET /upload/status返回已上传 chunk 列表,支持断点续传
POST /upload/complete检查 chunk 齐全性,合并文件,最终校验
POST /upload/cancel清理临时 chunk,关闭任务

uploadId 的作用

文件名不可靠(会重复、可改、不同用户可传同名),所以需要:

  • uploadId:上传任务唯一标识
  • userId:用户维度
  • fileHash:文件内容维度

数据表设计

upload_task 表

  • id, upload_id, user_id, file_name, file_size, file_hash
  • chunk_size, total_chunks, status, storage_type
  • created_at, updated_at

upload_chunk 表

  • id, upload_id, chunk_index, chunk_size, chunk_hash
  • status, storage_path, created_at

chunk 处理流程

  1. 校验元信息:uploadId 存在性、权限、chunkIndex 合法性、大小符合预期
  2. 落盘存储:本地磁盘、NAS、对象存储、分布式文件系统
  3. 更新状态:记录 chunk 成功、存储位置、大小、哈希
  4. 幂等返回:相同 chunk 重复上传直接返回成功

分块合并

调用 /upload/complete 时:

  1. 检查 chunk 齐全:确认 0~N-1 都存在
  2. 按顺序合并:严格按 chunkIndex 顺序
  3. 生成最终文件:写入最终存储目录或对象存储
  4. 校验最终 hash:确认与原始文件一致
  5. 更新任务状态:改为 completedmerge_failed

幂等性设计

chunk 上传接口必须幂等,因为:

  • 网络重试非常常见
  • 前端超时没收到响应会重发
  • 不幂等会导致重复写入、状态混乱

唯一键设计:(upload_id, chunk_index)

直传对象存储优化

大文件经业务服务中转的问题:

  • 业务服务带宽压力大
  • 服务实例被长连接拖住
  • 成本高、扩容麻烦

优化方案:

  1. 前端请求业务后端拿上传凭证/签名
  2. 后端返回临时上传地址
  3. 前端直接把 chunk 传到对象存储
  4. 前端上传完后通知业务后端”完成”
  5. 业务后端只负责记录元数据和校验

边界与易混淆点

  • 合并时磁盘占用:同时存在原 chunk、合并临时文件、最终文件,20GB 文件可能占用近 40GB
  • 并发合并保护:不能让同一任务被多次同时合并,需要加锁或 CAS
  • 多实例部署:chunk 可能落到不同机器,要用共享存储或对象存储,状态放数据库/Redis
创建于 2026/3/28 更新于 2026/5/27