Быстрое параллельное выкачивание списка файлов AWS S3 Buckets на Python

В AWS S3 нет папок, только плоское пространство имен.

Для эффективного распределения объектов рекомендуется использовать хэши в качестве префиксов ключей (“имен файлов”).

Это обеспечивает лучшую производительность и масштабируемость.

Но как потом получить список объектов (“файлов”) в большом S3 Bucket с десятками тысяч или даже миллионами объектов?

Этот процесс может занять много минут, поскольку для AWS это единый гигантский список, собираемый со множества серверов.

Для решения этой проблемы я создал класс на Python под названием S3BucketObjects, который эффективно создает списки объектов для гигантских S3 Bucket.

Async

S3BucketObjects использует aiobotocore для неблокирующих операций ввода-вывода. Это позволяет эффективно работать параллельно.

Интеллектуальный параллелизм

Хотя в S3 нет реальных папок, S3BucketObjects симулирует рекурсивный обход папок, используя параметр Delimiter в вызове API list_objects AWS S3. Этот параметр заставляет AWS использовать указанный символ (/) как разделитель логических “папок”, в итоге list_objects возвращает результат как два списка - объекты и “подпапки”, а не полный список объектов с данным префиксом, как происходит без параметра Delimiter.

S3BucketObjects начинает с перечисления объектов по указанному префиксу (корневой каталог), используя разделитель для получения списка объектов и списка “подпапок” вместо того чтобы запрашивать полный список объектов.

Затем он рекурсивно вызывает list_objects для каждой дочерней “подпапки”, рассматривая их новые корени для обхода.

Чтобы уменьшить количество необходимых вызовов API, S3BucketObjects использует две ключевые оптимизации.

Ограничение глубины рекурсии

Вы можете указать максимальную глубину рекурсии (max_depth), чтобы ограничить, как глубоко обходить структуру каталогов.

На указанной глубине S3BucketObjects будет запрашивать объекты как плоский список, без дальнейшей рекурсии.

Это может значительно уменьшить количество необходимых вызовов API, особенно для S3 Bucket с глубоко вложенными “подпапками”.

Группировка префиксов

S3BucketObjects интеллектуально группирует префиксы “папок”, чтобы минимизировать количество необходимых вызовов API.

Вместо перечисления объектов для каждой отдельной “папки” (что требовало бы отдельного вызова API для каждой “папки”), он группирует “папки” по общим префиксам и делает один вызов API для каждой группы префиксов.

Например, для:

folder0001/
folder0002/
folder0003/
..
folder9999/

Вместо выполнения тысяч вызовов API (по одному для каждой “папки”), S3BucketObjects с параметром max_folders=10 сгруппирует их всего в десять групп префиксов:

folder0
folder1
...
folder9

Это значительно уменьшает количество необходимых вызовов API, что приводит к более быстрому перечислению “папок” с большим количеством “подпапок”.

Сочетая асинхронные операции, рекурсивный обход с использованием параметра “Delimiter”, контроль глубины и интеллектуальную группировку префиксов, S3BucketObjects может в десятки раз улучшить производительность.

Использование

См. документацию.

Утилита командной строки

Пакет async-s3 также включает утилиту командной строки для удобных экспериментов с вашими S3 Bucket.

as3 du s3://my-bucket/my-key -l 1 -f 20 -r 3

Эта команда показывает размер и количество объектов в s3://my-bucket/my-key, ограничивая глубину рекурсии до 1.

Если на одном уровне больше 20 папок, он пытается сгруппировать их по префиксам.

Запрос повторяется три раза, и вычисляется среднее время.