Подтвердить что ты не робот

Могу ли я передать загрузку файла на S3 без заголовка содержимого?

Я работаю на машине с ограниченной памятью, и я бы хотел загрузить динамически генерируемый (не-диск) файл потоковым способом на S3. Другими словами, я не знаю размер файла при загрузке, но я знаю его до конца. Обычно запрос PUT имеет заголовок Content-Length, но, возможно, есть способ обойти это, например, использовать многостраничный или фрагментированный контент-тип.

S3 может поддерживать потоковые загрузки. Например, см. Здесь:

http://blog.odonnell.nu/posts/streaming-uploads-s3-python-and-poster/

Мой вопрос: могу ли я сделать то же самое, не указывая длину файла в начале загрузки?

4b9b3361

Ответ 1

Вы должны загрузить файл в 5MiB + кусках через S3 multipart API. Каждый из этих фрагментов требует Content-Length, но вы можете не загружать в память огромные объемы данных (100MiB +).

  • Инициировать многоточечную загрузку S3.
  • Собирайте данные в буфер до тех пор, пока этот буфер не достигнет нижнего предела размера блока S3 (5MiB). Генерируйте контрольную сумму MD5 при создании буфера.
  • Загрузите этот буфер как часть, сохраните ETag (прочитайте документы на этом).
  • Как только вы достигнете EOF своих данных, загрузите последний фрагмент (который может быть меньше 5MiB).
  • Завершите загрузку многостраничных файлов.

S3 позволяет до 10000 частей. Таким образом, выбрав размер 5MiB, вы сможете загружать динамические файлы до 50GiB. Должно быть достаточно для большинства случаев использования.

Однако: если вам нужно больше, вам нужно увеличить размер детали. Либо используя более высокий размер детали (например, 10MiB), либо увеличивая его во время загрузки.

First 25 parts:   5MiB (total:  125MiB)
Next 25 parts:   10MiB (total:  375MiB)
Next 25 parts:   25MiB (total:    1GiB)
Next 25 parts:   50MiB (total: 2.25GiB)
After that:     100MiB

Это позволит вам загружать файлы размером до 1 ТБ (ограничение S3 для одного файла составляет 5 ТБ прямо сейчас), не теряя память без необходимости.


Заметка на ссылку на блог Sean O'Donnells:

Его проблема отличается от вашей - он знает и использует Content-Length перед загрузкой. Он хочет улучшить ситуацию: многие библиотеки обрабатывают загрузки, загружая все данные из файла в память. В псевдокоде, который будет примерно таким:

data = File.read(file_name)
request = new S3::PutFileRequest()
request.setHeader('Content-Length', data.size)
request.setBody(data)
request.send()

Его решение делает это, получая Content-Length через файловую систему-API. Затем он передает данные с диска в поток запросов. В псевдокоде:

upload = new S3::PutFileRequestStream()
upload.writeHeader('Content-Length', File.getSize(file_name))
upload.flushHeader()

input = File.open(file_name, File::READONLY_FLAG)

while (data = input.read())
  input.write(data)
end

upload.flush()
upload.close()

Ответ 2

Поместите этот ответ здесь для других, если это поможет:

Если вы не знаете длину данных, которые вы передаете на S3, вы можете использовать S3FileInfo и его метод OpenWrite() для записи произвольных данных в S3.

var fileInfo = new S3FileInfo(amazonS3Client, "MyBucket", "streamed-file.txt");

using (var outputStream = fileInfo.OpenWrite())
{
    using (var streamWriter = new StreamWriter(outputStream))
    {
        streamWriter.WriteLine("Hello world");
        // You can do as many writes as you want here
    }
}

Ответ 3

Вы можете использовать инструмент командной строки gof3r для простого потока linux-труб:

$ tar -czf - <my_dir/> | gof3r put --bucket <s3_bucket> --key <s3_object>

Ответ 4

Подробнее о HTTP-запросах на множественную часть см. подробнее. Вы можете отправить файл в виде кусков данных в цель.

Ответ 5

Если вы используете Node.js, вы можете использовать плагин, например s3-streaming-upload, чтобы выполнить это довольно легко.