【问题标题】:How to upload small files to Amazon S3 efficiently in Python如何在 Python 中高效地将小文件上传到 Amazon S3
【发布时间】:2015-02-13 05:25:05
【问题描述】:

最近,我需要实现一个程序,以尽快将驻留在 Amazon EC2 中的文件上传到 Python 中的 S3。文件大小为30KB。

我尝试了一些解决方案,使用多线程、多处理、协程。以下是我在 Amazon EC2 上的性能测试结果。

3600(文件数量)* 30K(文件大小)~~ 105M(总计)--->

       **5.5s [ 4 process + 100 coroutine ]**
       10s  [ 200 coroutine ]
       14s  [ 10 threads ]

代码如下所示

用于多线程

def mput(i, client, files):
    for f in files:
        if hash(f) % NTHREAD == i:
            put(client, os.path.join(DATA_DIR, f))


def test_multithreading():
    client = connect_to_s3_sevice()
    files = os.listdir(DATA_DIR)
    ths = [threading.Thread(target=mput, args=(i, client, files)) for i in range(NTHREAD)]
    for th in ths:
        th.daemon = True
        th.start()
    for th in ths:
        th.join()

对于协程

client = connect_to_s3_sevice()
pool = eventlet.GreenPool(int(sys.argv[2]))

xput = functools.partial(put, client)
files = os.listdir(DATA_DIR)
for f in files:
    pool.spawn_n(xput, os.path.join(DATA_DIR, f))
pool.waitall()

用于多处理 + 协程

def pproc(i):
    client = connect_to_s3_sevice()
    files = os.listdir(DATA_DIR)
    pool = eventlet.GreenPool(100)

    xput = functools.partial(put, client)
    for f in files:
        if hash(f) % NPROCESS == i:
            pool.spawn_n(xput, os.path.join(DATA_DIR, f))
    pool.waitall()


def test_multiproc():
    procs = [multiprocessing.Process(target=pproc, args=(i, )) for i in range(NPROCESS)]
    for p in procs:
        p.daemon = True
        p.start()
    for p in procs:
        p.join()

本机配置为Ubuntu 14.04,2个CPU(2.50GHz),4G内存

达到的最高速度约为 19Mb/s (105 / 5.5)。总的来说,速度太慢了。有什么办法可以加快速度? stackless python 能不能做得更快?

【问题讨论】:

  • 有趣的是,如果我将文件大小设置为 1M,我可以获得 > 90Mb/s。
  • 问题比答案提供更多信息 =D 感谢协程示例

标签: python amazon-web-services amazon-s3 coroutine


【解决方案1】:

我最近需要将大约 5 TB 的小文件上传到 AWS,并通过在 ~/.aws/config 文件中设置更高的“max_concurrent_request”值来达到完全网络带宽 ~750Mbits(每台服务器 1 Gb 连接)而没有问题。

我通过 bash for 循环启动多个上传作业并将这些作业发送到不同的服务器,从而进一步加快了这个过程。

我也尝试过 python,例如。 s3-parallel-put,但我认为这种方法更快。当然如果文件太小应该考虑:压缩-->上传到EBS/S3并在那里解压

这里有一些可能有帮助的代码。

$cat .aws/config 
[default]
region = eu-west-1
output = text
s3 =
    max_concurrent_requests = 100

比启动多个 aws 复制作业,例如:

for folder in `ls`; do aws s3 cp $folder s3://<bucket>/$folder/whatever/; done

【讨论】:

  • 这个解决方案看起来不错,但它根本不在 python 中。
  • 当然,只是为了让其他人受益。
  • @Rami 您可以从 Python 调用 AWS CLI。
【解决方案2】:

我和你有同样的问题。我的解决方案是将数据发送到 AWS SQS,然后使用 AWS Lambda 将它们保存到 S3。

所以数据流看起来: 应用程序 -> SQS -> Lambda -> S3

整个过程是异步的,但接近实时:)

【讨论】:

  • 很好的解决方案,但不是有点开销?我的意思是很多非免费的基础设施只是为了执行异步上传。
  • 是的,肯定有开销。但它是完全异步且可扩展的(这正是我所需要的)。
  • @Hkar 但是如果我们没有大量的小文件 ..100000 需要上传到 S3 ..xml 文件的最大大小为 20kb ..跨度>
【解决方案3】:

此处提供了使用 Python boto SDK 到 Amazon S3 的并行上传时间示例:

除了自己编写代码之外,您还可以考虑调用AWS Command Line Interface (CLI),它可以并行上传。它也是用 Python 编写的,使用 boto。

【讨论】:

  • 该链接仅显示多线程和进程。不包括协程和多处理与协程的结合。在我的测试中,后者会获得更好的性能。
  • 我已经使用简单的 shell 命令“aws s3 cp myfolder s3://mybucket/myfolder”测试了 CLI。它的性能也很差。再说一次,我想说文章“使用 Boto 和 Python 中的线程进行并行 S3 上传”中的结果并不准确。作者如何仅用 10 个线程获得 70 倍 的速度。太棒了!
  • 我刚刚测试了“在 Python 中使用 Boto 和线程进行并行 S3 上传”中的方法,可以确认 70 倍的加速不准确。 Python 报告说我的代码几乎立即完成,但我可以通过监视 s3 上的实际内容看到上传仍在后台进行。不确定如何为这种方法获得真正准确的时间,但它看起来与其他方法相当。
  • @SohierDane 如果您希望脚本等到上传完成,您需要在 python 代码末尾加入进程/线程,这应该会给您准确的时间。否则线程会与父进程分离并自行完成,因此您的主要 python 脚本会立即存在。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-27
  • 2012-02-02
  • 2011-04-07
  • 2019-12-10
  • 2013-09-09
  • 2015-10-28
相关资源
最近更新 更多