如何在Python中有效地将小文件上传到Amazon S3

时间:2014-12-15 06:35:20

标签: python amazon-s3

最近,我需要实现一个程序,以尽可能快地将文件驻留在Amazon EC2中的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能做得更快吗?

3 个答案:

答案 0 :(得分:4)

使用Python boto SDK到Amazon S3的并行上传时间示例可在此处获取:

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

答案 1 :(得分:3)

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

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

我也试过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

答案 2 :(得分:1)

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

所以数据流看起来如下: app - &gt; SQS - &gt; Lambda - &gt; S3

整个过程是异步的,但几乎是实时的:)