后端状态管理与分块合并
后端大文件上传的接口设计、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 处理流程
- 校验元信息:uploadId 存在性、权限、chunkIndex 合法性、大小符合预期
- 落盘存储:本地磁盘、NAS、对象存储、分布式文件系统
- 更新状态:记录 chunk 成功、存储位置、大小、哈希
- 幂等返回:相同 chunk 重复上传直接返回成功
分块合并
调用 /upload/complete 时:
- 检查 chunk 齐全:确认 0~N-1 都存在
- 按顺序合并:严格按 chunkIndex 顺序
- 生成最终文件:写入最终存储目录或对象存储
- 校验最终 hash:确认与原始文件一致
- 更新任务状态:改为
completed或merge_failed
幂等性设计
chunk 上传接口必须幂等,因为:
- 网络重试非常常见
- 前端超时没收到响应会重发
- 不幂等会导致重复写入、状态混乱
唯一键设计:(upload_id, chunk_index)
直传对象存储优化
大文件经业务服务中转的问题:
- 业务服务带宽压力大
- 服务实例被长连接拖住
- 成本高、扩容麻烦
优化方案:
- 前端请求业务后端拿上传凭证/签名
- 后端返回临时上传地址
- 前端直接把 chunk 传到对象存储
- 前端上传完后通知业务后端”完成”
- 业务后端只负责记录元数据和校验
边界与易混淆点
- 合并时磁盘占用:同时存在原 chunk、合并临时文件、最终文件,20GB 文件可能占用近 40GB
- 并发合并保护:不能让同一任务被多次同时合并,需要加锁或 CAS
- 多实例部署:chunk 可能落到不同机器,要用共享存储或对象存储,状态放数据库/Redis