使用 boto3 时如何提高 AWS s3 上传速度?

Pet*_*tch 7 amazon-s3 boto3

嘿,有一些类似的问题,但没有一个完全像这样,而且相当多的问题已经存在多年并且已经过时了。

我在我的服务器上编写了一些代码,通过 boto3 方法 upload_file 使用密钥将 jpeg 照片上传到 s3 存储桶。最初这看起来很棒。这是一个将文件上传到 s3 的超级简单的解决方案。

问题是,我有用户。我的用户通过电话应用程序将他们的 jpeg 发送到我的服务器。虽然我承认我可以生成预先签名的上传 URL 并将它们发送到电话应用程序,但这需要对我们的电话应用程序和 API 进行大量重写。

所以我只希望手机应用程序将照片发送到服务器。然后我想将照片从服务器发送到 s3。我实现了这个,但它太慢了。我不能要求我的用户容忍这些缓慢的上传。

我能做些什么来加快速度?

我做了一些谷歌搜索,发现这个:https : //medium.com/@alejandro.millan.frias/optimizing-transfer-throughput-of-small-files-to-amazon-s3-or-anywhere-really-301dca4472a5

它建议解决方案是增加 TCP/IP 连接数。更多的 TCP/IP 连接意味着更快的上传。

好的,太好了!

我怎么做?如何增加 TCP/IP 连接数,以便更快地将单个 jpeg 上传到 AWS s3?

请帮忙。

Pie*_*e D 8

具有讽刺意味的是,我们已经使用boto3了多年awscli,并且我们都喜欢它们。

但是我们经常想知道为什么 awscli 的aws s3 cp --recursive, or aws s3 sync,通常比尝试通过 进行一堆上传要快得多boto3,即使使用concurrent.futures's ThreadPoolExecutoror ProcessPoolExecutor(并且您甚至不敢s3.Bucket在您的工作人员之间共享相同的内容:在文档,并且有充分的理由;令人讨厌的崩溃最终会在最不方便的时候发生)。

最后,我硬着头皮查看了 awscli 在boto3.

基于这个小小的探索,这里有一种方法可以通过使用内置的并发来加速将许多文件上传到 S3 boto3.s3.transfer,不仅适用于单个大文件的可能多部分,还适用于各种不同的文件。尺寸也是如此。据我所知,该功能并未通过文档boto3中描述的更高级别的 API 公开boto3

下列:

  1. 例如,用于boto3.s3.transfer创建一个TransferManager,与 awscli 使用的完全相同aws s3 sync

  2. 将最大线程数扩展到 20。

  3. 增加urllib3用于botocore匹配的底层最大池连接容量(默认情况下,它最多使用 10 个连接)。

  4. 为您提供可选的回调功能(此处使用tqdm进度条进行演示,但当然您可以使用任何您想要的回调)。

  5. 快速(超过100MB / s的--tested上的EC2实例)。

在这里放了一个完整的例子作为要点,其中包括生成 500 个随机 csv 文件,总共约 360MB。但是如果你假设你在filelist下面有一堆文件,总共total_size字节:

import os
import boto3
import botocore
import boto3.s3.transfer as s3transfer
import tqdm

botocore_config = botocore.config.Config(max_pool_connections=20)
s3client = boto3.client('s3', config=botocore_config)

transfer_config = s3transfer.TransferConfig(
    use_threads=True,
    max_concurrency=20,
)

bucket_name = '<your-bucket-name>'
s3junkdir = 'some/path/for/junk'

%%time
progress = tqdm.tqdm(
    desc='upload',
    total=total_size, unit='B', unit_scale=1,
    position=0,
    bar_format='{desc:<10}{percentage:3.0f}%|{bar:10}{r_bar}')

s3t = s3transfer.create_transfer_manager(s3client, transfer_config)
for src in filelist:
    dst = os.path.join(s3junkdir, os.path.basename(src))
    s3t.upload(
        src, bucket_name, dst,
        subscribers=[
            s3transfer.ProgressCallbackInvoker(progress.update),
        ],
    )

s3t.shutdown()  # wait for all the upload tasks to finish
progress.close();
Run Code Online (Sandbox Code Playgroud)