[英]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),您可以通過兩種方式解決此問題。 您可以:
.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.