我有一个托管在 nginx(反向代理 - proxy_pass 指令)后面的 go-chi (golang) Web 应用程序,它接受文件上传,然后上传到 AWS S3。
带有文件的请求是通过带有
content-type
的 multipart/form-data 的 POST 请求发送的。
应用程序然后接收请求并创建一个
multipart.file
类型,根据我的理解,这个整个文件都分配在内存中。
我愿意接受 5GB - 10GB 范围内的文件,并且无法增加此大小的服务器内存,因为我只有 2GB。
S3 具有分段上传方法,允许将文件的部分内容上传到 S3。
我已经在下面的
go
中实现了这个分段文件上传,我面临的问题是我觉得有重复的工作,因为go-http库已经在部分分配内存以使*multipart.file
类型本质上做我的事情我在下面做。
有没有办法将ParseMultipartForm()
中
go-http库创建的这些部分文件直接上传到S3以避免整个文件在内存中的分配?(上传文件流为它进来了)
避免在go-http中解析和分配
mutlipart.file
并将其直接加载到磁盘,然后使用multipart s3方法上传文件部分会更好吗?尽管我相信我仍然需要在内存中流式传输整个文件才能执行此操作,但由于我没有足够的内存,这将无法工作
Nginx 在将其传递给 Web 应用程序之前是否也会解析并分离该文件?
我在下面实现了 S3 分段上传的轻型 POC。
partBufSize := int64(10000000)
byteOffset := int64(0)
for {
remainingStreamBytes := uploadSize - bytesOffset
if remainingStreamBytes < partBufSize {
partBufSize = remainingStreamBytes
}
_, _ = uploadedFile.Seek(bytesOffset, io.SeekStart)
filePartBuffer := make([]byte, partBufSize)
_, err := uploadedFile.Read(filePartBuffer)
if err != nil {
if err == io.EOF {
break
}
log.Error().Msg(err.Error())
}
uploadPartRes, err := s3Client.UpParts(&aws.PartObjectInput{
Key: uploadPartsRequest.Key,
Body: bytes.NewReader(filePartBuffer),
PartNum: aws.Int64(int64(count)),
UpId: uploadPartsRequest.UploadId,
PartSize: aws.Int64(partBufSize),
})
if err != nil {
log.Error().Msg(err.Error())
}
bytesOffset = bytesOffset + partBufSize
compParts = append(compParts, &s3.CompletedPart{
ETag: uploadPartRes.ETag,
PartNumber: aws.Int64(int64(count)),
})
count++
}
应用程序然后接收请求并创建一个 multipart.file 类型,根据我的理解,整个文件都分配在内存中。
我不太明白这一点。如果这是您编码的方式,那么就不要这样做:Go 提供了
mime/multipart.Reader
,可用于读取 multipart/form-data
编码的负载。Content-Type
标头字段的值,并使用 mime.ParseMediaType
函数解析它,以获取“边界”的值——用于分隔多部分有效负载中各部分的字符串。multipart.Reader
。io.Reader
,它将提供该部分的字节。对这些字节执行任何您想要的操作 - 可能使用 io.Copy
或 io.CopyN
将它们放入活动的 POST 请求中。这样您就可以控制要提供的确切缓冲量。