web-dev-qa-db-ja.com

content-lengthヘッダーなしでS3へのファイルアップロードをストリーミングできますか?

メモリが限られているマシンで作業していますが、動的に生成された(ディスクからではない)ファイルをストリーミング方式でS3にアップロードしたいと思います。つまり、アップロードを開始したときのファイルサイズはわかりませんが、終わりまでにはわかります。通常、PUT要求にはContent-Lengthヘッダーがありますが、マルチパートまたはチャンク化されたコンテンツタイプを使用するなど、おそらくこれを回避する方法があります。

S3はストリーミングアップロードをサポートできます。たとえば、こちらをご覧ください。

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

私の質問は、アップロードの開始時にファイルの長さを指定せずに同じことを達成できますか?

53
Tyler

S3のマルチパートAPI 経由で5MiB +チャンクでファイルをアップロードする必要があります。これらの各チャンクにはContent-Lengthが必要ですが、大量のデータ(100MiB +)をメモリにロードすることを回避できます。

  • S3を開始しますMultipart Upload
  • そのバッファーがS3のチャンクサイズの下限(5MiB)に達するまで、バッファーにデータを収集します。バッファーの構築中にMD5チェックサムを生成します。
  • そのバッファをPartとしてアップロードし、ETagを保存します(そのドキュメントを読んでください)。
  • データのEOFに到達したら、最後のチャンク(5MiBよりも小さい場合があります)をアップロードします。
  • マルチパートアップロードを完了します。

S3では、最大10,000個の部品を使用できます。そのため、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

これにより、メモリを不必要に浪費することなく、最大1TBのファイルをアップロードできます(単一ファイルのS3の制限は現在5TBです)。


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()
60

役に立つ場合に備えて、他の人のためにこの答えをここに入れてください:

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
    }
}
_
5
mwrichardson

gof3r コマンドラインツールを使用して、Linuxパイプをストリーミングできます。

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

HTTPマルチパートエンティティリクエストの詳細を参照してください。ファイルをデータの塊としてターゲットに送信できます。

1
Kris

Node.jsを使用している場合、 s3-streaming-upload のようなプラグインを使用して、これを非常に簡単に実行できます。

1
nathanpeck