【发布时间】:2021-06-01 00:52:55
【问题描述】:
我需要找到上传大量图片(最多几千张)的最佳方式,平均每张图片的大小约为 6MB。我们的服务是用 Python 编写的。
我们有以下流程:
- 有一个服务创建了一个 BlobServiceClient。我们正在使用 CertificateCredentials 进行身份验证
- 服务在 Linux 上的容器中运行并用 Python 代码编写
- 服务正在接收一条消息,其中包含 6 到 9 个图像作为每个 Numpy ndarray + JSON 元数据对象
- 每次收到消息时,我们都会使用 ThreadPoolExecutor 将所有文件和 JSON 文件发送到存储,其中 max_threads = 20
- 我们没有使用库的异步版本
修剪和简化的代码将如下所示(下面将不起作用,只是一个说明,azurestorageclient 是 Azure Python SDK 的外包装。它有一个 BlobServiceClient 实例,我们用于创建容器和上传 Blob):
def _upload_file(self,
blob_name: str,
data: bytes,
blob_type: BlobType,
length=None):
blob_client = self._upload_container.get_blob_client(blob_name)
return blob_client.upload_blob(data, length=len(data), blob_type=BlobType.BlockBlob)
def _upload(self, executor: ThreadPoolExecutor, storage_client: AzureStorageClient,
image: ndarray, metadata: str) -> (Future, Future):
DEFAULT_LOGGER.info(f"Uploading image blob: {img_blob_name} ...")
img_upload_future = executor.submit(
self.upload_file,
blob_name=img_blob_name, byte_array=image.tobytes(),
content_type="image/jpeg",
overwrite=True,
)
DEFAULT_LOGGER.info(f"Uploading JSON blob: {metadata_blob_name} ...")
metadata_upload_future = executor.submit(
self.upload_file,
blob_name=metadata_blob_name, byte_array=metadata_json_bytes,
content_type="application/json",
overwrite=True,
)
return img_upload_future, metadata_upload_future
def send(storage_client: AzureStorageClient,
image_data: Dict[metadata, ndarray]):
with ThreadPoolExecutor(max_workers=_THREAD_SEND_MAX_WORKERS) as executor:
upload_futures = {
image_metadata: _upload(
executor=executor,
storage_client=storage_client,
image=image,
metadata=metadata
)
for metadata, image in image_data.items()
}
当在信号强度波动很大的慢速网络中上传文件时,我们观察到此类服务的性能非常差。
我们现在正在尝试寻找和衡量如何提高性能的不同选项:
- 我们会先将文件存储到硬盘中,然后不时将它们以更大的块上传
- 我们认为上传单个大文件的性能应该更好(例如,将 100 个文件转换为 zip/tar 文件)
- 我们认为在连接不良时减少并行作业的数量也应该会更好
- 我们考虑使用 AzCopy 而不是 Python
关于如何在这种情况下工作,是否有任何其他建议或 Python 中不错的代码示例?或者也许我们应该更改用于上传数据的服务?例如使用 ssh 连接到 VM 并以这种方式上传文件(我怀疑它会更快,但得到了这样的建议)。
迈克
【问题讨论】:
标签: python azure performance azure-storage