
Объектные хранилища с доступом на базе S3 API — это, возможно, лучшее решение для хранения больших объемов данных. Однако при загрузке крупных файлов могут возникнуть проблемы. Например, долгая передача данных из-за сетевых ограничений или таймауты и обрывы соединения. Как ни крути, а интернет даже здесь диктует свои условия. Попробуем их обойти с помощью мультипарт-загрузки.
Привет! Меня зовут Гришин Александр, я продакт-менеджер в Selectel и отвечаю за развитие объектного хранилища и облачных баз данных. В этой статье я расскажу, как загружать большие файлы в S3 с помощью мультипарт-загрузки, используя Python и boto3. Под катом вы узнаете, как работает этот механизм и как его настроить для эффективной работы.
Скоро выпустим новый комикс о путешествиях ИБ-специалиста! Регистрируйтесь, чтобы узнать о публикации первыми. Бонусом сможете выиграть один из 15 комплектов призов.
Используйте навигацию, если не хотите читать текст полностью:
→ Как работает мультипарт-загрузка в S3
→ Пример на Python
→ Оптимизация и рекомендации
→ А нужен ли код
Как работает мультипарт-загрузка в S3
Мультипарт-загрузка состоит из нескольких этапов.
1. Инициализация загрузки — создание уникального идентификатора загрузки.
response = s3_client.create_multipart_upload(Bucket=BUCKET_NAME, Key=KEY) upload_id = response["UploadId"]
Этот запрос создает мультипарт-загрузку и возвращает UploadId, ��оторый используется для загрузки частей файла.
2. Разделение файла на части и их параллельная отправка.
response = s3_client.upload_part( Bucket=BUCKET_NAME, Key=KEY, PartNumber=part_number, UploadId=upload_id, Body=data )
3. Завершение загрузки и сборка частей в единый объект:
s3_client.complete_multipart_upload( Bucket=BUCKET_NAME, Key=KEY, UploadId=upload_id, MultipartUpload={"Parts": parts} )
4. При необходимости — отмена загрузки (например, если загрузка не удалась).

Схема разбиения объекта на парты и их параллельная загрузка в S3.

Пример на Python
Реализацию мультипарт-загрузки я разделю на два этапа: работа в панели управления и работа на клиенте. Итак.
Часть работы в панели управления Selectel
В целом, здесь нам нужно просто создать и настроить контейнер объектного хранилища. Очень подробный пошаговый гайд вы найдете в недавней статье моего коллеги. Я же перечислю только основные шаги:
- Перейдите в панель управления → Объектное хранилище и нажмите Создать контейнер.
- Выберите тип адресации vHosted. Что касается типа контейнера, то для работы с чувствительными данными подойдет приватный, а если планируете реализовать доступ к контенту без авторизации, выберите публичный.
- Создайте служебного пользователя с ролью администратор объектного хранилища и доступом в нужный проект.
- Создайте S3-ключ в панели управления.
- Сохраните Access Key и Secret Key (будьте внимательны: ключи не хранятся в наших системах и показываются только один раз).

Работа с сервисными пользователями в панели управления.
Часть работы на клиенте
Прежде всего, установите библиотеку boto3. Это делается командой в терминале:
pip install boto3
Теперь подключаем библиотеки и пишем код для загрузки файла в объектное хранилище, используя мультипарт-загрузку:
import boto3 import os # Настройки подключения к Selectel S3 S3_ENDPOINT = "https://s3.ru-1.storage.selcloud.ru" # Укажите ваш региональный endpoint ACCESS_KEY = "ТУТ_ВАШ_ACCESS_KEY" SECRET_KEY = "ТУТ_ВАШ_SECRET_KEY" BUCKET_NAME = "4habr" FILE_PATH = "/Users/alex/Downloads/1.mp4" # Файл для загрузки KEY = "thebigboy2.mp4" # Название объекта в S3 # Создаем S3 клиент s3_client = boto3.client( "s3", endpoint_url=S3_ENDPOINT, aws_access_key_id=ACCESS_KEY, aws_secret_access_key=SECRET_KEY ) # 1. Инициализация мультипартийной загрузки response = s3_client.create_multipart_upload(Bucket=BUCKET_NAME, Key=KEY) upload_id = response["UploadId"] print(f"Multipart Upload ID: {upload_id}") # 2. Разбиение файла на части и загрузка PART_SIZE = 1 * 1024 * 1024 # Размер одной части (1MB) parts = [] file_size = os.path.getsize(FILE_PATH) try: with open(FILE_PATH, "rb") as f: part_number = 1 while True: data = f.read(PART_SIZE) if not data: break # Загружаем часть файла response = s3_client.upload_part( Bucket=BUCKET_NAME, Key=KEY, PartNumber=part_number, UploadId=upload_id, Body=data ) # Добавляем информацию о части parts.append({"PartNumber": part_number, "ETag": response["ETag"]}) print(f"Uploaded part {part_number}") part_number += 1 # 3. Завершаем загрузку s3_client.complete_multipart_upload( Bucket=BUCKET_NAME, Key=KEY, UploadId=upload_id, MultipartUpload={"Parts": parts} ) print("Multipart upload completed!") except Exception as e: print("Upload failed:", str(e)) s3_client.abort_multipart_upload(Bucket=BUCKET_NAME, Key=KEY, UploadId=upload_id)
Как работает этот код:
- create_multipart_upload — создаем загрузку и получаем UploadId;
- читаем файл частями по 1 МБ и загружаем их с помощью upload_part;
- сохраняем ETag загруженных частей для финальной сборки;
- complete_multipart_upload — объединяем загруженные части в единый объект;
- если произошла ошибка, вызываем abort_multipart_upload для отмены загрузки.
Результат
Объект загружен. Можно делиться им с друзьями. Чтобы увидеть результат работы со стороны хранилища, снова зайдите в панель управления. Перейдите в нужный проект в объектном хранилище и включите отображение служебных контейнеров в настройках (это необходимо, чтобы увидеть парты загруженного объекта). В основном контейнере вы увидите ссылку на загруженный объект, а в служебном — парты этого объекта. На скриншоте ниже это шесть объектов размером до 1 МБ.

Листинг мультипартов в интерфейсе хранилища.
Оптимизация и рекомендации
Для примера выше я установил размер парта 1 МБ, но это было сделано умышленно с целью демонстрации. Не стоит это повторять. В реальных проектах для загрузки больших файлов лучше использовать значения существенно больше, хотя бы 50-100 МБ.
Для обработки ошибок добавьте повторную попытку загрузки парта в случае сетевых проблем. А также настройте удаление ненужных частей в случае таких ошибок. В Selectel мы всегда храним все составные части загрузки, поскольку не знаем, в какой момент со стороны клиента может прийти CompleteMultipartUpload и нужны ли еще клиенту эти части.
А нужен ли код
В этой статья я использовал код только для демонстрации работы мультипартовой загрузки в объектное хранилище Selectel. Для большего удобства рекомендую использовать готовые приложения, поддерживающие такую функциональность из коробки. К ним относятся:
Пользуясь случаем, выделю именно rclone т. к. недавно мы стали официальными технологическими партнерами и получили нативную поддержку нашей услуги в этом клиенте.
Если у вас остались вопросы, смело задавайте их в комментариях, все обсудим. И поделитесь своим опытом, как вы ускоряете загрузку ваших приложений в объектное хранилище.
