在构建获得场景视频 API 开发过程中,视频上传是至关重要的一环。对于动辄几百 MB 甚至几个 GB 的视频文件,一次性上传很容易因为网络波动、服务器压力等原因失败。因此,分片上传成为解决大文件上传问题的常用方案。本文将深入探讨 CC 视频平台的分片上传服务设计与实践,分享我们在架构设计、底层原理、代码实现以及避坑经验方面的思考。
分片上传原理与流程
分片上传的核心思想是将大文件分割成多个小文件(片),然后并发或串行地将这些小文件上传到服务器。服务器接收到所有分片后,再将它们合并成完整的文件。
基本流程如下:
- 初始化上传: 客户端向服务器发送初始化请求,服务器生成一个唯一的上传 ID (Upload ID),用于标识本次上传任务。
- 分片上传: 客户端将文件分割成多个分片,并携带 Upload ID 和分片序号,逐个上传分片数据。
- 校验与合并: 服务器接收到所有分片后,根据 Upload ID 校验分片的完整性,并按照分片序号将它们合并成完整的文件。
- 完成上传: 客户端发送完成上传请求,服务器进行最终的校验,并返回上传结果。
关键技术点
- 分片大小的选择: 分片大小直接影响上传效率和服务器压力。通常,1MB - 10MB 是一个比较合适的范围。太小会增加请求次数,太大则可能因为单个分片上传失败而导致重传。
- 断点续传: 在上传过程中,如果发生网络中断或上传失败,客户端可以从上次中断的位置继续上传,而不需要重新上传整个文件。这需要服务器记录已上传的分片信息。
- 并发上传: 客户端可以同时上传多个分片,从而提高上传速度。但需要注意控制并发数量,避免服务器压力过大。
- MD5 校验: 在上传过程中,可以使用 MD5 算法对分片数据进行校验,确保数据完整性。
CC视频平台分片上传架构设计
我们的 CC 视频平台采用以下架构设计来实现分片上传服务:
sequenceDiagram
participant Client
participant Nginx
participant API Gateway
participant Upload Service
participant Object Storage
Client->>Nginx: 初始化上传请求
Nginx->>API Gateway: 反向代理
API Gateway->>Upload Service: 创建上传任务,获取 Upload ID
Upload Service->>API Gateway: 返回 Upload ID
API Gateway->>Client: 返回 Upload ID
Client->>Nginx: 分片上传请求 (携带 Upload ID)
Nginx->>API Gateway: 反向代理
API Gateway->>Upload Service: 接收分片数据
Upload Service->>Object Storage: 上传分片数据
Client->>Nginx: 完成上传请求 (携带 Upload ID)
Nginx->>API Gateway: 反向代理
API Gateway->>Upload Service: 合并分片,校验文件完整性
Upload Service->>API Gateway: 返回上传结果
API Gateway->>Client: 返回上传结果
架构说明:
- 客户端: 负责文件分片、上传、断点续传等功能。
- Nginx: 作为反向代理服务器,负责负载均衡和请求转发。我们使用了 Nginx 的 upstream 模块配置了多个 Upload Service 实例,提高系统的可用性。
- API Gateway: 负责请求路由、鉴权、限流等功能。
- Upload Service: 核心服务,负责处理上传请求、管理分片数据、合并文件等功能。我们使用 Spring Boot 构建了 Upload Service,并使用 Redis 存储 Upload ID 和分片信息。
- Object Storage: 对象存储服务,用于存储分片数据和最终的完整文件。我们选择了阿里云 OSS 作为对象存储服务。
Upload Service 核心代码示例 (Java)
@RestController
@RequestMapping("/upload")
public class UploadController {
@Autowired
private UploadService uploadService;
@PostMapping("/init")
public ResponseEntity<String> initUpload() {
String uploadId = uploadService.initUpload(); // 创建 Upload ID
return ResponseEntity.ok(uploadId);
}
@PostMapping("/part")
public ResponseEntity<String> uploadPart(@RequestParam("uploadId") String uploadId,
@RequestParam("partNumber") int partNumber,
@RequestParam("file") MultipartFile file) throws IOException {
uploadService.uploadPart(uploadId, partNumber, file.getInputStream()); // 上传分片
return ResponseEntity.ok("success");
}
@PostMapping("/complete")
public ResponseEntity<String> completeUpload(@RequestParam("uploadId") String uploadId) {
uploadService.completeUpload(uploadId); // 合并分片
return ResponseEntity.ok("success");
}
}
Nginx 配置示例
upstream upload_service {
server 192.168.1.101:8080;
server 192.168.1.102:8080;
server 192.168.1.103:8080;
}
server {
listen 80;
server_name upload.example.com;
location /upload/ {
proxy_pass http://upload_service; # 反向代理到 Upload Service
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 100M; # 允许上传的最大文件大小
}
}
实战避坑经验
- Upload ID 的唯一性: 确保 Upload ID 的全局唯一性,避免不同上传任务之间发生冲突。
- 分片丢失处理: 定期检查 Redis 中是否存在长时间未完成的 Upload ID,清理过期数据,防止资源浪费。
- 并发控制: 根据服务器的负载能力,合理设置并发上传的数量,避免服务器压力过大。
- 错误处理: 完善的错误处理机制至关重要。例如,当上传失败时,需要返回详细的错误信息,方便客户端进行重试。
- 安全考虑: 对上传的文件进行安全扫描,防止恶意文件上传。
希望以上关于 CC 视频平台分片上传服务的设计与实践经验分享,能帮助你更好地理解和应用分片上传技术。在实际开发中,还需要根据具体的业务场景进行调整和优化。
冠军资讯
架构师李明