LoginSignup
8
3
この記事誰得? 私しか得しないニッチな技術で記事投稿!

S3 のマルチパートアップロードは複数ファイルの集約にも使えちゃう

Last updated at Posted at 2023-06-29

S3 の Multipart upload とは

マルチパートアップロードは、単一のオブジェクトを複数に分割してアップロードできる機能です。分割された個々の部分 (part) は並列でアップロードできるため、スループットの向上やネットワークエラー時の影響軽減といった効果が期待できます。

大きなサイズのオブジェクトをアップロードまたはコピーする際にはマルチパートアップロードの使用が推奨されます。AWS CLI の高レベルコマンド (aws s3) ではファイルサイズに応じて自動的にマルチパートアップロードを実行するため、意識せずお世話になっている方も多いのはないかと思います。

S3 のコスト最適化の文脈でも、不完全なマルチパートアップロードを削除するという設定でお目にかかるケースが多いですね。

複数ファイルの集約にも使える

マルチパートアップロードは単一のオブジェクトを複数に分割し、アップロードを効率化することを目的として提供されています。分割してアップロードされたファイルは最終的には元の単一オブジェクトに結合されるわけですが、それを利用して複数の別オブジェクトを単一のオブジェクトに集約することも可能です。

以降は AWS CLI を使用する場合の例です。
3 つのダミーファイルを作成し、マルチパートアップロードでファイルを結合します。この程度であればローカルで cat コマンドで連結してアップロードした方が速いし、楽やんというご指摘はごもっともですが、ここでは置いておいてください。

  1. ダミーファイルの準備
    パートファイルの最小サイズは 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
    
  2. マルチパートアップロードの開始
    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")
    
  3. 各ファイルをアップロード
    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}]}"
    

    ちょっと無理やり感ありますね。。。

  4. マルチパートアップロードの完了
    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\""
    }
    
  5. 結果確認
    15 MB の単一ファイルが作成されています。

    image.png

    ローカルにダウンロードし、中身を確認すると想定通り結合されていました。

    $ 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 に配信する方がよいでしょう。

以上です。

8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3