我正在通过 boto3 使用分段上传将大型数据库转储 (~85 GB) 上传到 Amazon S3 存储桶。但是,我一直遇到这个错误:
botocore.exceptions.ClientError: An error occurred (InvalidArgument) when calling the UploadPart operation: Part number must be an integer between 1 and 10000, inclusive.
这是我的代码的相关部分:
from boto3.s3.transfer import TransferConfig
def upload_encrypted_dbdump(self, ciphertext_stream):
s3 = self.s3_session_client()
prev_total_size = 77309411328 # Previous file size, around 77 GB
# Amazon S3's maximum number of parts for multipart upload
max_parts = 10000
# Calculate the new size with a 10% increase
adjusted_size = int(prev_total_size * 1.1)
# Calculate the part size with rounding up
part_size = (adjusted_size + max_parts - 1) // max_parts
print(f"Calculated part size: {part_size} bytes")
s3_response = s3.upload_fileobj(
Fileobj=ciphertext_stream,
Bucket=self.s3_bucket,
Key=f'{self.s3_folder}/{self.s3_dbdump_name}',
ExtraArgs={'ACL': 'bucket-owner-full-control'},
Config=TransferConfig(multipart_chunksize=part_size)
)
我尝试过的步骤: 我根据之前备份的大小动态计算了部分大小,将其增加了 10%。
示例:如果先前的大小为 77 GB,我计算新的大小为 adjustment_size = int(77309411328 * 1.1) → 85040352460 字节。 然后,我将此尺寸除以 max_parts = 10000 来计算零件尺寸。
part_size = (调整后的_size + max_parts - 1) // max_parts 对于本示例,计算结果为:part_size = 85040352460 / 10000 ≈ 8504036 字节。 当我运行代码时,遇到“零件号必须是 1 到 10000 之间的整数(含)”错误。
我观察到的:
当我手动将 max_parts 设置为 1000 时效果很好,但是当我将其更改为 10,000 甚至 9,000 时,我得到了同样的错误。
我还尝试了 math.ceil(adjusted_size / max_parts) 来计算零件尺寸,但问题仍然存在。
问题:
当计算出的 part_size 似乎有效时,为什么我会收到“零件编号必须是 1 到 10000 之间的整数”错误?
如有任何帮助,我们将不胜感激!谢谢。
我认为零件编号错误可能是因为
ciphertext_stream
字节大小大于计算的 adjusted_size
,因此除以 part_size
时零件总数超过 10000。您应该使用 ciphertext_stream
的实际字节大小来计算每个部分的大小。如果 ciphertext_stream
是 io.BytesIO
类型,则可以使用 getbuffer().nbytes
from boto3.s3.transfer import TransferConfig
def upload_encrypted_dbdump(self, ciphertext_stream):
s3 = self.s3_session_client()
# Amazon S3's maximum number of parts for multipart upload
max_parts = 10000
# Calculate the new size with a 10% increase
stream_size = ciphertext_stream.getbuffer().nbytes
# Calculate the part size with rounding up
part_size = (stream_size + max_parts - 1) // max_parts
print(f"Calculated part size: {part_size} bytes")
s3_response = s3.upload_fileobj(
Fileobj=ciphertext_stream,
Bucket=self.s3_bucket,
Key=f'{self.s3_folder}/{self.s3_dbdump_name}',
ExtraArgs={'ACL': 'bucket-owner-full-control'},
Config=TransferConfig(multipart_chunksize=part_size)
)