背景
大文件上传需求,缺点如下
- 上传时间长
- 上传过程中,如果断网/刷新页面,需要重新上传
思维链
浏览器对于同一个域名的请求,同时建立的TCP连接数有限制,比如Chrome是6个,而HTTP2之前的协议,是串行请求的,所以如果一个文件过大,会导致请求时间过长。
客户端断开网络后,其上下文会丢失,需要重新上传。
我们需要提高上传的速度,以及上传服务的可靠性。
- 将文件拆分成多个进行上传,充分利用多个TCP通道
- 利用HTTP2的TCP多路复用,拉高并发请求数,一般可以到100+
- 利用文件hash + 索引,实现断点续传
实现流程
- 客户端:计算文件的hash值
- 客户端:获取服务端的临时目录下文件名为
hash-索引值的所有子文件名称列表 - 客户端:利用blob.prototype.slice,将文件拆分成多个子文件,每个子文件的文件名:hash值 + 索引
- 客户端:以ReadableStream的形式并发上传服务器没有的子文件
- 服务端:接收到子文件上传请求后,在临时目录下创建一个写入流,将子文件写入目录下。
- 如果上传请求完成,则下一步
- 如果上传请求失败,则删除这个残缺的子文件
- 客户端:上传完所有子文件的请求后,发起一个合并请求
- 服务端:接收到合并请求后,将所有
hash-索引值的子文件合并成一个文件,落盘。
QA
-
内存控制
- 客户端使用ReadableStream的方式传输
- 将请求上来的文件,直接通过写入流,写到存储中
- 合并文件时,使用写入流来合并。
-
并发提升
- 使用HTTP2的TCP多路复用
- 起一个消息队列的服务用于接收请求
- 异步执行逻辑
- 多进程 - PM2
- 多实例集群
- 使用高并发语言,比如Golang等
-
分片分多少 一般分片大小在1MB-5MB之间比较常见,具体取决于:
- 网络环境:网络越不稳定,分片尽量小
- 服务器处理能力:IO并发越强,分片尽量小