
Объектные хранилища с доступом на базе 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 т. к. недавно мы стали официальными технологическими партнерами и получили нативную поддержку нашей услуги в этом клиенте.
Если у вас остались вопросы, смело задавайте их в комментариях, все обсудим. И поделитесь своим опытом, как вы ускоряете загрузку ваших приложений в объектное хранилище.
Автор: GrishinAlex