分片上传与 ETag 的计算
目标
用底层 API 亲自执行分段上传,手工计算分段 ETag 并使其与服务器的值一致,再掌握清理中断的上传。
为什么重要
分段上传在很多情况下由 SDK 代劳,所以很容易在不了解内部机制的情况下一带而过。但有两点必须知道。第一是 ETag。通过分段上传的对象,其 ETag 不是内容的 md5,而是把各分段 md5 的二进制值依次拼接后再次取 md5 的结果,末尾还会附加分段数。不知道这一点,就会在“用 ETag 验证却对不上”上耗掉好几个小时。第二是中断的上传。未完成的分段上传,其各分段会占用存储空间,却不会出现在对象列表中。客户端崩溃或部署期间中断的上传如果累积几个月,账单上就会无缘无故出现数百 GB。这是 AWS 成本泄漏的常见项目,本实验的第 7 步就是对它的应对。
步骤
- 把
/root/mp/big.bin创建为恰好 25165824 字节(24MiB)。内容必须可复现(例如重复 0x00–0xFF)。 - 在
/root/mp/parts.txt中写入part_size=5242880、parts=5、last_part=4194304三行。4 个 5MiB 的分段,再加上最后一个 4MiB 的分段。 - 用
/root/mp/mp.py对lab-media/big/big.bin发起分段上传,并把 UploadId 保存到/root/mp/upload_id.txt。长度必须不少于 32 个字符。 - 上传 5 个分段,并把每个响应的 ETag 按
<파트번호> <etag>(占位符依次为分段编号、ETag)的格式写入/root/mp/part_etags.txt,共 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=<값>(占位符均为具体的值)两行。两个值必须相同。 - 对
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两行。
参考
- 分段规则:最多 10,000 个;除最后一个之外,每个分段至少 5MiB;每个分段最大 5GiB
- ETag 计算:用
bytes.fromhex()把各分段的 md5 转成二进制并依次拼接,对整体再取 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 profilelocal沿用上一项实验(s3-basics)第 1 步中创建的那个。 - 常见错误 1:把分段 md5 按十六进制字符串原样拼接——必须是二进制值。
- 常见错误 2:没有中止失败的上传,导致分段悄悄堆积。
创建大文件
把 /root/mp/big.bin 创建为恰好 25165824 字节(24MiB)。内容必须可复现(例如重复 0x00–0xFF)。
内容每次都要相同,以后才能比较哈希。用固定的模式填充。
计算分段划分
在 /root/mp/parts.txt 中写入 part_size=5242880、parts=5、last_part=4194304 三行。4 个 5MiB 的分段,再加上最后一个 4MiB 的分段。
除最后一个分段外,每个分段都规定了最小大小。剩下的部分就是最后一个分段。
发起分段上传
用 /root/mp/mp.py 对 lab-media/big/big.bin 发起分段上传,并把 UploadId 保存到 /root/mp/upload_id.txt。长度必须不少于 32 个字符。
发起之后会得到一个标识符。有了这个标识符才能上传分段。
上传分段并收集 ETag
上传 5 个分段,并把每个响应的 ETag 按 <파트번호> <etag>(占位符依次为分段编号、ETag)的格式写入 /root/mp/part_etags.txt,共 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=<값>(占位符均为具体的值)两行。两个值必须相同。
把各分段 md5 的二进制值依次拼接后再取 md5,然后附加分段数。用的是二进制值,而不是十六进制字符串。
只发起而不完成,然后中止
对 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 两行。
用 sha256 与原文件比较。然后用数字写出三条分段规则。