簡體   English   中英

如何將 Azure Blob 流式傳輸到 AWS S3?

[英]How to stream Azure Blob to AWS S3?

我需要將一個大的 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)

Blob 的副本位於 memory 中,因為您似乎在 go 中閱讀它。 您正在初始化io.BytesIO的兩個實例,但隨后您正在使用blob_client.download_blob().readinto(input_stream)讀取整個 blob。

我認為您應該嘗試的是讀取(並放置)blob的塊,一次一個塊,避免將其全部讀取到memory。

在上傳方面 (s3),您可以通過兩種方式解決此問題。 您可以:

  • 使用 S3 部分(multipart)上傳機制(使用.upload()發起,然后.upload_part()上傳每個部分(chunk),或者
  • .upload_fileobj()提供類似 object 的文件,該文件將負責一次提供一個塊

據我所知,似乎blob_client.download_blob()已經返回了一個名為StorageStreamDownloader的類似 object 的文件,它實現了一個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,
    )

就像我提到的 - 我現在無法訪問任何 blob 存儲/s3 資源,所以我盯着代碼。 但大體思路應該是一樣的。 通過使用 blob 的.chunks() ,您應該只將一小部分數據提取到 memory 中,將其上傳(使用 MPU)到 S3 並立即丟棄。

基於這里的samu答案是一個工作示例,缺少與完成分段上傳相關的部分

def copy_from_azure_to_s3(conn_str:str,container_name:str,file_name:str,bucket_name:str,s3):

    #initiate Azure client
    blob_client = BlobClient.from_connection_string(
        conn_str=con_string,
        container_name=container_name,
        blob_name=file_name,
        max_chunk_get_size=50*1024*1024 #min size for multipart upload is 5MB, it needs to be higher than that
    )

    #define multipart upload
    mpu = s3.create_multipart_upload(Bucket=bucket_name, Key=file_name)
    mpu_id = mpu["UploadId"]

    blob = blob_client.download_blob()

    #store info about individual parts
    etags=[]

    #stream it to s3
    for part_num, chunk in enumerate(blob.chunks(), start=1):
        response= s3.upload_part(
            Body=chunk,
            Bucket=bucket_name,
            Key=file_name,
            UploadId=mpu_id,
            PartNumber=part_num,
        )
        etags.append({'ETag': response['ETag'],'PartNumber':part_num})

    #finish the upload
    s3.complete_multipart_upload(
        Bucket=bucket_name,
        Key=file_name,
        UploadId=mpu_id,
        MultipartUpload={
            'Parts': etags
        },

    )

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM