题目
设计高并发Spring MVC文件上传服务,支持大文件分片上传与断点续传
信息
- 类型:问答
- 难度:⭐⭐⭐
考点
Spring MVC文件处理机制, 高并发优化策略, 断点续传实现原理, 分布式存储集成
快速回答
实现高并发大文件上传服务的核心要点:
- 使用
MultipartFile配合分片上传策略处理大文件 - 通过MD5校验实现断点续传和文件完整性验证
- 采用线程池+异步处理提升并发能力
- 集成Redis存储上传状态实现分布式支持
- 结合对象存储(如S3/MinIO)保存文件分片
1. 核心实现原理
分片上传流程:
- 前端将大文件切割为固定大小分片(如5MB)
- 每个分片独立上传,携带文件MD5、分片序号等元数据
- 服务端校验分片完整性后暂存
- 全部分片上传完成后合并为完整文件
断点续传机制:
- 服务端记录每个文件的分片上传状态(Redis存储)
- 客户端首次请求返回已上传的分片索引
- 基于HTTP 206 Partial Content实现续传
2. 关键代码实现
Spring MVC控制器:
@PostMapping("/upload")
public ResponseEntity<?> uploadChunk(
@RequestParam("file") MultipartFile file,
@RequestParam("chunkIndex") int chunkIndex,
@RequestParam("totalChunks") int totalChunks,
@RequestParam("fileMd5") String fileMd5) {
// 1. 校验分片MD5
String chunkMd5 = DigestUtils.md5Hex(file.getInputStream());
if (!chunkMd5.equals(request.getHeader("Chunk-MD5"))) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("MD5 mismatch");
}
// 2. 存储分片(异步操作)
storageService.saveChunk(fileMd5, chunkIndex, file.getBytes());
// 3. 更新Redis状态
redisTemplate.opsForHash().put(fileMd5, "chunk_" + chunkIndex, "1");
return ResponseEntity.ok().build();
}分片合并逻辑:
public void mergeChunks(String fileMd5, String fileName) throws IOException {
try (BufferedOutputStream outputStream = new BufferedOutputStream(
new FileOutputStream("/final/" + fileName))) {
for (int i = 0; i < totalChunks; i++) {
// 从分布式存储读取分片
byte[] chunk = minioClient.getChunk(fileMd5, i);
outputStream.write(chunk);
outputStream.flush();
}
}
// 删除临时分片
minioClient.cleanChunks(fileMd5);
}3. 高并发优化策略
- 异步处理: 使用
@Async+线程池分离IO操作@Async("uploadTaskExecutor")
public CompletableFuture<Void> asyncSaveChunk(...) { ... } - 资源隔离: 独立线程池处理上传任务,避免阻塞Tomcat线程
- 分布式存储: 使用MinIO/S3存储分片,支持水平扩展
- 限流熔断: 集成Resilience4j实现请求限流
4. 最佳实践
- 分片大小: 根据网络环境动态调整(前端可计算最优分片大小)
- 状态管理: Redis数据结构设计:
Key: file:{md5} | Field: chunk_{index} | Value: 0/1 - 安全防护:
- 限制单用户并发上传数
- 校验Content-Length头部防DoS攻击
- 设置临时文件自动清理机制
5. 常见错误与规避
- 内存溢出: 避免用
byte[]直接存储大文件分片
解决方案: 使用InputStream配合临时文件存储 - 分片丢失: 网络中断导致分片不完整
解决方案: 实现分片超时回收机制(TTL+定时任务) - 合并失败: 文件锁冲突
解决方案: 采用原子操作重命名最终文件
6. 扩展知识
- 秒传技术: 服务端校验文件MD5,若已存在直接返回成功
- 跨域优化: 预检请求(OPTIONS)缓存减少开销
- 流量控制: 基于令牌桶算法限制用户上传速率
- 云原生方案: 通过Kafka解耦上传与处理流程