如何将 Azure Blob 流式传输到 AWS S3?

And*_*rei 5 python amazon-s3 azure-storage-blobs

我需要将一个大型 Azure Blob 复制到 AWS S3,而不在内存中保留它的副本。经过一番谷歌搜索后,我发现了一堆我在以下脚本中组合的示例。尽管如此,这仍然将数据加载到内存中。有什么好的方法可以避免吗?

import boto3
from azure.storage.blob import BlobClient

with io.BytesIO() as input_stream, io.BytesIO() as output_stream:
    blob_client = BlobClient.from_connection_string(
        conn_str=AZURE_CONNECTION_STRING,
        container_name=container,
        blob_name=filename,
    )
    blob_client.download_blob().readinto(input_stream)

    input_stream.seek(0)
    shutil.copyfileobj(input_stream, output_stream)
    output_stream.seek(0)

    boto3.resource("s3").Object(BUCKET_NAME, s3_key).put(Body=output_stream)
Run Code Online (Sandbox Code Playgroud)

sam*_*amu 3

该 blob 的副本位于内存中,因为您似乎正在一口气读取它。您正在初始化 的两个实例io.BytesIO,但随后您正在使用 读取整个 blob blob_client.download_blob().readinto(input_stream)

我认为你应该尝试的是读取(并放入)blob 块,一次一大块,避免将其全部读取到内存中。

在上传方面 (s3),您可以通过两种方式解决该问题。您可以:

  • 使用S3部分(multipart)上传机制(使用.upload()来发起,然后.upload_part()上传每个部分(chunk),或者
  • 提供一个类似文件的对象,.upload_fileobj()负责一次提供一个块

据我所知,似乎blob_client.download_blob()已经返回了一个名为 的类文件对象StorageStreamDownloader,它实现了一个chunks()方法。我找不到合适的文档,但根据源代码,似乎它返回了一个您可以使用的迭代器。

因此,请考虑这样的事情(我目前无法访问任何 azure/s3 服务,因此此代码可能无法开箱即用):

import boto3
from boto3.s3.transfer import TransferConfig, S3Transfer

blob_client = BlobClient.from_connection_string(
    conn_str=AZURE_CONNECTION_STRING,
    container_name=container,
    blob_name=filename,
)
s3 = boto3.resource('s3')

mpu = s3.create_multipart_upload(Bucket=BUCKET_NAME, Key=s3_key)
mpu_id = mpu["UploadId"]

blob = blob_client.download_blob()
for part_num, chunk in enumerate(blob.chunks()):
    s3.upload_part(
        Body=chunk,
        Bucket=BUCKET_NAME,
        Key=s3_key,
        UploadId=mpu_id,
        PartNumber=part_num,
    )
Run Code Online (Sandbox Code Playgroud)

就像我提到的 - 我现在无法访问任何 blob 存储/s3 资源,因此我查看了代码。但总体思路应该是一样的。通过使用.chunks()blob,您应该只将一小块数据提取到内存中,将其上传(使用 MPU)到 S3 并立即丢弃。