Как загрузить небольшие файлы в Amazon S3 эффективно в Python

В последнее время мне нужно как можно быстрее реализовать программу для загрузки файлов в Amazon EC2 на S3 в Python. Размер файлов - 30 КБ.

Я пробовал некоторые решения, используя несколько потоков, множественную обработку, совместную работу. Ниже приведен мой результат теста производительности на 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 процессора (2.50 ГГц), 4G памяти

Самая высокая достигнутая скорость составляет 19 Мбит/с (105/5.5). В целом, это слишком медленно. Любой способ ускорить его? Может ли ускоренный python делать это быстрее?

Ответ 1

Пример параллельного времени загрузки для Amazon S3 с помощью Python boto SDK можно найти здесь:

Вместо написания кода вы можете также обратиться к интерфейсу командной строки AWS, который может выполнять закачки в параллельны друг другу. Он также написан на Python и использует boto.

Ответ 2

Мне недавно потребовалось загрузить около 5 ТБ небольших файлов в AWS и без проблем достигнет полной пропускной способности сети ~ 750 Мбит (соединение 1 Гб на сервер), установив более высокое значение "max_concurrent_request" в файле ~/.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

Ответ 3

У меня та же проблема, что и у вас. Мое решение было отправить данные в AWS SQS, а затем сохранить их на S3 с помощью AWS Lambda.

Итак, поток данных выглядит: приложение → SQS → Lambda → S3

Весь процесс асинхронен, но почти в режиме реального времени:)