大文件上传

221 阅读2分钟

背景

大文件上传需求,缺点如下

  1. 上传时间长
  2. 上传过程中,如果断网/刷新页面,需要重新上传

思维链

浏览器对于同一个域名的请求,同时建立的TCP连接数有限制,比如Chrome是6个,而HTTP2之前的协议,是串行请求的,所以如果一个文件过大,会导致请求时间过长。

客户端断开网络后,其上下文会丢失,需要重新上传。

我们需要提高上传的速度,以及上传服务的可靠性。

  • 将文件拆分成多个进行上传,充分利用多个TCP通道
  • 利用HTTP2的TCP多路复用,拉高并发请求数,一般可以到100+
  • 利用文件hash + 索引,实现断点续传

实现流程

  1. 客户端:计算文件的hash值
  2. 客户端:获取服务端的临时目录下文件名为hash-索引值的所有子文件名称列表
  3. 客户端:利用blob.prototype.slice,将文件拆分成多个子文件,每个子文件的文件名:hash值 + 索引
  4. 客户端:以ReadableStream的形式并发上传服务器没有的子文件
  5. 服务端:接收到子文件上传请求后,在临时目录下创建一个写入流,将子文件写入目录下。
    • 如果上传请求完成,则下一步
    • 如果上传请求失败,则删除这个残缺的子文件
  6. 客户端:上传完所有子文件的请求后,发起一个合并请求
  7. 服务端:接收到合并请求后,将所有hash-索引值的子文件合并成一个文件,落盘。

QA

  1. 内存控制

    • 客户端使用ReadableStream的方式传输
    • 将请求上来的文件,直接通过写入流,写到存储中
    • 合并文件时,使用写入流来合并。
  2. 并发提升

    • 使用HTTP2的TCP多路复用
    • 起一个消息队列的服务用于接收请求
    • 异步执行逻辑
    • 多进程 - PM2
    • 多实例集群
    • 使用高并发语言,比如Golang等
  3. 分片分多少 一般分片大小在1MB-5MB之间比较常见,具体取决于:

    • 网络环境:网络越不稳定,分片尽量小
    • 服务器处理能力:IO并发越强,分片尽量小