マルチパートアップロードとETagの計算
目標
マルチパートアップロードを低水準のAPIで自分で実行し、マルチパートETagを手で計算してサーバーの値と一致させたうえで、中断されたアップロードを整理するところまでを身につけます。
なぜ重要なのか
マルチパートは、SDKが勝手にやってくれることが多く、内部を知らずに通り過ぎやすいものです。しかし、2つの点で必ず知っておく必要があります。1つ目は、ETagです。マルチパートでアップロードされたオブジェクトのETagは、内容のmd5ではなく、各パートのmd5のバイナリ値をつなげてもう一度md5した値で、末尾にパート数が付きます。これを知らないと、「ETagで検証したのに合わない」で何時間も費やします。2つ目は、中断されたアップロードです。完了していないマルチパートのパートは、ストレージ容量を占めますが、オブジェクトの一覧には見えません。クライアントが死んだり、デプロイ中に切れたりしたアップロードが数か月溜まると、請求書に理由のない数百GBが現れます。AWSのコスト漏れの常連で、このラボのステップ7が、その対応です。
ステップ
/root/mp/big.binを、ちょうど25165824バイト(24MiB)で作成してください。内容は再現可能である必要があります(例: 0x00–0xFFの繰り返し)。/root/mp/parts.txtに、part_size=5242880、parts=5、last_part=4194304の3行を書いてください。5MiBのパート4つに、最後の4MiBのパートが付きます。/root/mp/mp.pyで、lab-media/big/big.binに対するマルチパートアップロードを開始し、UploadIdを/root/mp/upload_id.txtに保存してください。32文字以上である必要があります。- 5つのパートをアップロードし、各レスポンスのETagを
/root/mp/part_etags.txtに<파트번호> <etag>(プレースホルダーはパート番号です)の形式で5行書いてください。 - アップロードを完了してください。
aws --profile local s3api head-object --bucket lab-media --key big/big.binのContentLengthが25165824で、ETagが-5で終わっている必要があります。 /root/mp/etag_calc.pyでマルチパートETagを手で計算し、/root/mp/etag_calc.txtにcalculated=<값>とserver=<값>の2行(プレースホルダーは値です)を書いてください。2つの値が同じである必要があります。lab-media/big/orphan.binに対して、アップロードを開始だけして中止してください。/root/mp/abort.outにuploads_before=1 uploads_after=0を書きます。- オブジェクトを
/root/mp/downloaded.binにダウンロードし、sha256を元と比較して、/root/mp/verify.txtにsha_match=trueを書いてください。同じファイルに、max_parts=10000、min_part_bytes=5242880の2行も書きます。
参考
- パートのルール: 最大10,000個、最後を除く各パートは最小5MiB、パートの最大は5GiB
- ETagの計算: 各パートのmd5を
bytes.fromhex()でバイナリ化してつなげ、その全体をmd5してから-<파트수>(プレースホルダーはパート数です)を付けます - 未完了のアップロードの照会は、
list_multipart_uploadsまたはaws s3api list-multipart-uploads --bucket lab-mediaで行います。 - 資格情報は、
/opt/fixtures/s3/creds.envのS3_ENDPOINT・S3_ACCESS_KEY・S3_SECRET_KEYです。awsプロファイルlocalは、前のラボ(s3-basics)のステップ1で作ったものをそのまま使います。 - よくあるミス1: パートのmd5を16進文字列のままつなげてしまうこと。バイナリ値である必要があります。
- よくあるミス2: 失敗したアップロードを中止せず、パートが静かに溜まってしまうこと。
大きなファイルを作る
/root/mp/big.binを、ちょうど25165824バイト(24MiB)で作成してください。内容は再現可能である必要があります(例: 0x00–0xFFの繰り返し)。
内容が毎回同じでないと、あとでハッシュを比較できません。固定されたパターンで埋めてください。
パートの分割を計算する
/root/mp/parts.txtに、part_size=5242880、parts=5、last_part=4194304の3行を書いてください。5MiBのパート4つに、最後の4MiBのパートが付きます。
最後のパートを除く各パートには、最小サイズが決まっています。残りが最後のパートです。
マルチパートアップロードを開始する
/root/mp/mp.pyで、lab-media/big/big.binに対するマルチパートアップロードを開始し、UploadIdを/root/mp/upload_id.txtに保存してください。32文字以上である必要があります。
開始すると、識別子を受け取ります。この識別子があって初めて、パートをアップロードできます。
パートをアップロードしてETagを集める
5つのパートをアップロードし、各レスポンスのETagを/root/mp/part_etags.txtに<파트번호> <etag>(プレースホルダーはパート番号です)の形式で5行書いてください。
パート番号は1から始まります。各レスポンスのETagを、順番に集めておかないと、完了できません。
アップロードを完了する
アップロードを完了してください。aws --profile local s3api head-object --bucket lab-media --key big/big.binのContentLengthが25165824で、ETagが-5で終わっている必要があります。
パート番号とETagの一覧を一緒に渡します。完了後、オブジェクトのサイズが元と同じである必要があります。
マルチパートETagを手で再現する
/root/mp/etag_calc.pyでマルチパートETagを手で計算し、/root/mp/etag_calc.txtにcalculated=<값>とserver=<값>の2行(プレースホルダーは値です)を書いてください。2つの値が同じである必要があります。
各パートのmd5のバイナリ値をつなげて、もう一度md5し、パート数を付けます。16進文字列ではなく、バイナリ値です。
開始だけして中止する
lab-media/big/orphan.binに対して、アップロードを開始だけして中止してください。/root/mp/abort.outにuploads_before=1 uploads_after=0を書きます。
中止しないと、パートがストレージ容量を占め続けます。中止後、未完了の一覧が空になっている必要があります。
ダウンロードして完全性を確認し、ルールをまとめる
オブジェクトを/root/mp/downloaded.binにダウンロードし、sha256を元と比較して、/root/mp/verify.txtにsha_match=trueを書いてください。同じファイルに、max_parts=10000、min_part_bytes=5242880の2行も書きます。
sha256で、元と比較します。そして、パートのルール3つを、数字で書いてください。