S3 の Multipart upload とは
マルチパートアップロードは、単一のオブジェクトを複数に分割してアップロードできる機能です。分割された個々の部分 (part) は並列でアップロードできるため、スループットの向上やネットワークエラー時の影響軽減といった効果が期待できます。
大きなサイズのオブジェクトをアップロードまたはコピーする際にはマルチパートアップロードの使用が推奨されます。AWS CLI の高レベルコマンド (aws s3
) ではファイルサイズに応じて自動的にマルチパートアップロードを実行するため、意識せずお世話になっている方も多いのはないかと思います。
S3 のコスト最適化の文脈でも、不完全なマルチパートアップロードを削除するという設定でお目にかかるケースが多いですね。
複数ファイルの集約にも使える
マルチパートアップロードは単一のオブジェクトを複数に分割し、アップロードを効率化することを目的として提供されています。分割してアップロードされたファイルは最終的には元の単一オブジェクトに結合されるわけですが、それを利用して複数の別オブジェクトを単一のオブジェクトに集約することも可能です。
以降は AWS CLI を使用する場合の例です。
3 つのダミーファイルを作成し、マルチパートアップロードでファイルを結合します。この程度であればローカルで cat コマンドで連結してアップロードした方が速いし、楽やんというご指摘はごもっともですが、ここでは置いておいてください。
-
ダミーファイルの準備
パートファイルの最小サイズは 5 MB であるため、5 MB のファイルを 3 つ作成しておきます。dd if=/dev/zero of=file1.txt bs=5M count=1 && echo "hoge" >> file1.txt dd if=/dev/zero of=file2.txt bs=5M count=1 && echo "fuga" >> file2.txt dd if=/dev/zero of=file3.txt bs=5M count=1 && echo "piyo" >> file3.txt
-
マルチパートアップロードの開始
create-multipart-upload
を実行し、レスポンスのUploadId
を変数に格納します。BUCKET_NAME="your-bucket" TARGET_FILE="aggregated-file.txt" upload_id=$(aws s3api create-multipart-upload --bucket "${BUCKET_NAME}" --key "${TARGET_FILE}" | jq -r ".UploadId")
-
各ファイルをアップロード
upload-part
でパートファイルをアップロードします。レスポンスの ETag 値を JSON 形式でparts
変数に格納しています。これは後ほどマルチパートアップロードを完了する際に必要なリクエスト情報です。part_number=1 parts="{\"Parts\": [" while read part_file do etag=$(aws s3api upload-part --bucket "${BUCKET_NAME}" --key "${TARGET_FILE}" --body "${part_file}" --part-number ${part_number} --upload-id "${upload_id}" | jq -r ".ETag") parts="${parts}{\"ETag\": ${etag},\"PartNumber\": ${part_number}}," part_number=$((part_number+1)) done <<EOF file1.txt file2.txt file3.txt EOF parts="${parts/%?/}" parts="${parts}]}"
ちょっと無理やり感ありますね。。。
-
マルチパートアップロードの完了
complete-multipart-upload
を実行してマルチパートアップロードを完了します。aws s3api complete-multipart-upload --multipart-upload "${parts}" --bucket "${BUCKET_NAME}" --key "${TARGET_FILE}" --upload-id "${upload_id}" { "ServerSideEncryption": "aws:kms", "SSEKMSKeyId": "arn:aws:kms:ap-northeast-1:123456789012:key/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "Location": "https://your-bucket.s3.ap-northeast-1.amazonaws.com/aggregated-file.txt", "Bucket": "your-bucket", "Key": "aggregated-file.txt", "ETag": "\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-x\"" }
-
結果確認
15 MB の単一ファイルが作成されています。ローカルにダウンロードし、中身を確認すると想定通り結合されていました。
$ aws s3 cp s3://kosu/${TARGET_FILE} . download: s3://kosu/aggregated-file.txt to ./aggregated-file.txt $ cat ./aggregated-file.txt hoge fuga piyo
まとめ
S3 のマルチパートアップロード機能で、複数のオブジェクトを単一のオブジェクトに集約できることを確認しました。が、本記事はこういった使い方を推奨するものでありません。
マルチパートアップロードは大きなサイズのオブジェクトアップロードを効率化するための機能です。単純にファイル集約を行う目的であれば、パフォーマンスやコスト面で最適ではありません。
例えばリクエストログをレコードごとにアップロードするなど、数 KB 程度の小さなサイズのファイルを大量にアップロードする場合は、S3 の Put 料金が高額になりがちです。
マルチパートアップロードアップロードで集約することを考えた場合、以下の点からこういったユースケースには明らかに向かないことがわかります。
- パートファイルの最小サイズが 5 MB
- パートファイルのアップロードは通常の put 料金がかかる
この場合、Amazon Kinesis Data Firehose でログデータをバッファリングして、S3 に配信する方がよいでしょう。
以上です。