TT Lab
开始
学习 学习路径 课程

对象存储与 S3

分片上传与 ETag 的计算

在 TT Lab 中继续学习

目标

用底层 API 亲自执行分段上传,手工计算分段 ETag 并使其与服务器的值一致,再掌握清理中断的上传。

为什么重要

分段上传在很多情况下由 SDK 代劳,所以很容易在不了解内部机制的情况下一带而过。但有两点必须知道。第一是 ETag。通过分段上传的对象,其 ETag 不是内容的 md5,而是把各分段 md5 的二进制值依次拼接后再次取 md5 的结果,末尾还会附加分段数。不知道这一点,就会在“用 ETag 验证却对不上”上耗掉好几个小时。第二是中断的上传。未完成的分段上传,其各分段会占用存储空间,却不会出现在对象列表中。客户端崩溃或部署期间中断的上传如果累积几个月,账单上就会无缘无故出现数百 GB。这是 AWS 成本泄漏的常见项目,本实验的第 7 步就是对它的应对。

步骤

  1. 把 /root/mp/big.bin 创建为恰好 25165824 字节(24MiB)。内容必须可复现(例如重复 0x00–0xFF)。
  2. 在 /root/mp/parts.txt 中写入 part_size=5242880、parts=5、last_part=4194304 三行。4 个 5MiB 的分段,再加上最后一个 4MiB 的分段。
  3. 用 /root/mp/mp.py 对 lab-media/big/big.bin 发起分段上传,并把 UploadId 保存到 /root/mp/upload_id.txt。长度必须不少于 32 个字符。
  4. 上传 5 个分段,并把每个响应的 ETag 按 <파트번호> <etag>(占位符依次为分段编号、ETag)的格式写入 /root/mp/part_etags.txt,共 5 行。
  5. 完成上传。aws --profile local s3api head-object --bucket lab-media --key big/big.bin 的 ContentLength 必须是 25165824,ETag 必须以 -5 结尾。
  6. 用 /root/mp/etag_calc.py 手工计算分段 ETag,并在 /root/mp/etag_calc.txt 中写入 calculated=<값> 和 server=<값>(占位符均为具体的值)两行。两个值必须相同。
  7. 对 lab-media/big/orphan.bin 只发起上传,然后中止。在 /root/mp/abort.out 中写入 uploads_before=1 uploads_after=0。
  8. 把对象下载为 /root/mp/downloaded.bin,将其 sha256 与原文件比较,并在 /root/mp/verify.txt 中写入 sha_match=true。同一个文件中还要写入 max_parts=10000、min_part_bytes=5242880 两行。

参考

创建大文件

把 /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 与原文件比较。然后用数字写出三条分段规则。