сеньорчикОткрыть в Telegram
← вся теориятеория к собесу · Docker и Kubernetes

Объектное хранилище (S3)

Объектное хранилище (S3/MinIO)

Как только у сервиса появляются пользовательские файлы - аватары, документы, экспортные CSV - встаёт вопрос: где их держать. Соблазн положить в PostgreSQL сильный (одна транзакция, один бэкап), но на собесе и на проде это считается антипаттерном. Разберёмся, почему файлы уходят в объектное хранилище и как с ним правильно работать.

Проверяют не знание конкретного облака, а модель: плоская адресация, presigned-доступ, multipart, lifecycle. Это переносится между S3, MinIO, Ceph и любым S3-совместимым хранилищем.

Почему не в БД, и как устроен S3

Блобы в БД раздувают её размер, замедляют бэкапы и вымывают кэш полезных строк, а раздача файлов нагружает драгоценные коннекты к базе. Поэтому файл кладут в объектное хранилище, а в БД оставляют лишь ключ объекта и метаданные (размер, тип, кто загрузил). Хранилище дёшево держит большие объекты и отдаёт их напрямую, часто через CDN (content delivery network).

S3 это плоское key-value: внутри бакета объект адресуется строковым ключом. Никаких настоящих каталогов нет - слэши в ключе (users/42/avatar.png) лишь соглашение, по которому можно листать по префиксу. Поэтому «переименовать папку» = переложить все объекты с новым префиксом, а листинг «по папке» это фильтр, а не обход дерева.

бакет
именованный контейнер объектов
ключ
строковый адрес объекта внутри бакета
метаданные
размер/тип/владелец - в БД рядом с ключом

Presigned URL, multipart и lifecycle

Чтобы не гонять гигабайты через бэкенд, клиенту выдают presigned URL - подписанную ссылку с сроком годности: по ней он качает (GET) или заливает (PUT) объект прямо в S3. Ключи наружу не уходят, доступ ограничен конкретным объектом и временем. Это снимает нагрузку с сервера и держит бакет приватным.

Крупные файлы заливают multipart upload - частями, с повтором только упавшей части и параллелизмом. А чтобы хранилище не росло вечно, вешают lifecycle-правила: удалить объекты старше N дней, перевести в холодный класс, вычистить старые версии и брошенные multipart-загрузки.

url = s3.generate_presigned_url(
    "get_object",
    Params={"Bucket": "media", "Key": key},
    ExpiresIn=900,  # 15 минут
)

Как отвечать: «Зачем файлы в S3, а не в PostgreSQL?»

Потому что блобы в БД раздувают её, бэкапы и кэш, а раздача файлов ест коннекты к базе. Объектное хранилище дёшево держит большие объекты и отдаёт их напрямую или через CDN, а в БД я оставляю только ключ объекта и метаданные. Скачивание и загрузку выношу на presigned URL - клиент ходит в S3 сам, минуя бэкенд, без раскрытия ключей.

Ответ показывает, что человек отделяет хранение блобов от хранения данных и понимает presigned-доступ, а не тянет файлы через сервер и БД.

На чём валят

  • Класть сам файл в БД (bytea/base64) - раздувает базу, бэкапы и кэш; в БД только ключ и метаданные.
  • Открывать бакет публично или слать ключи в браузер вместо presigned URL с коротким expiry.
  • Один PUT на многогигабайтный файл вместо multipart - рвётся на сети, без докачки.
  • Забыть lifecycle: копятся старые версии и брошенные multipart - платишь за мусор.

Проверьте себя

Пять вопросов из банка по этой подтеме. Всего их 12, остальные разбираются в тренажёре.

  1. #object_storage_s31 / 5
    Как устроена адресация объекта в S3?
    A)Это настоящая файловая система с каталогами, inode и правами доступа на папки
    B)Плоское пространство: бакет + ключ (строка), «папки» — иллюзия по префиксу
    C)Объект адресуется автоинкрементным числовым id, как строка в таблице
    D)Путь со слэшами создаёт реальные вложенные папки, которые надо заводить заранее
    показать ответ и разбор
    +B)Плоское пространство: бакет + ключ (строка), «папки» — иллюзия по префиксу

    // разбор: S3 — плоское key-value: внутри бакета объект адресуется строковым ключом. Слэши в ключе (photos/2026/a.jpg) — соглашение для листинга по префиксу, а не настоящие каталоги. Поэтому «переименование папки» — это перекладка всех объектов с новым префиксом.

  2. #object_storage_s32 / 5
    Фронту надо отдать пользователю файл из приватного бакета, не проксируя гигабайты через бэкенд. Что выдать клиенту?
    A)Постоянный публичный URL, открыв бакет на чтение всему интернету
    B)Свои access key и secret прямо в браузер, чтобы клиент сходил в S3 сам
    C)Presigned URL — временную подписанную ссылку прямо в S3
    D)Ссылку на эндпоинт бэкенда, который скачивает объект и стримит его через себя каждому клиенту
    показать ответ и разбор
    +C)Presigned URL — временную подписанную ссылку прямо в S3

    // разбор: Presigned URL — ссылка с подписью и сроком годности: бэкенд генерирует её своими ключами, а клиент качает (GET) или заливает (PUT) объект напрямую в S3, минуя сервер. Ключи наружу не уходят, доступ ограничен конкретным объектом и временем жизни ссылки.

  3. #object_storage_s33 / 5
    Presigned URL сгенерирован с expiry 15 минут. Что это ограничивает?
    A)Сколько всего раз файл можно скачать по этой ссылке за всё время
    B)Время, после которого сам объект удалится из бакета автоматически
    C)Максимальный размер объекта, который разрешено передать по данной ссылке в мегабайтах
    D)Окно, в течение которого по ссылке можно обратиться к объекту
    показать ответ и разбор
    +D)Окно, в течение которого по ссылке можно обратиться к объекту

    // разбор: Срок presigned URL — временное окно валидности подписи: пока не истёк, ссылкой можно пользоваться (в т.ч. несколько раз), после — S3 отвергает запрос. Короткий expiry снижает риск утечки ссылки, но не удаляет объект и не считает скачивания.

  4. #object_storage_s34 / 5
    Сервис заливает в S3 файлы по 5 ГБ и иногда падает на сетевых сбоях в середине. Какой механизм S3 тут профильный?
    A)Multipart upload — заливка частями с дозагрузкой упавших
    B)Single PUT одним запросом — просто поднять таймаут HTTP до нескольких часов
    C)Записать файл в БД транзакцией, а потом синхронизировать его в S3 фоном
    D)Сжать файл gzip'ом на лету — тогда обрыв соединения перестанет происходить
    показать ответ и разбор
    +A)Multipart upload — заливка частями с дозагрузкой упавших

    // разбор: Multipart upload разбивает объект на части, каждая грузится и подтверждается отдельно, а в конце S3 склеивает их по завершающему запросу. Упавшую часть повторяют, не перезаливая весь файл; параллельная заливка частей ещё и ускоряет отправку крупных объектов.

  5. #object_storage_s35 / 5
    Зачем в S3 включают версионирование объектов?
    A)Чтобы ускорить чтение объекта за счёт кэширования его последней версии на диске
    B)Хранить прежние версии ключа — защита от перезаписи и удаления
    C)Чтобы объект автоматически сжимался при каждой новой заливке того же ключа
    D)Чтобы бакет начал поддерживать транзакции с откатом сразу по группе объектов
    показать ответ и разбор
    +B)Хранить прежние версии ключа — защита от перезаписи и удаления

    // разбор: С версионированием запись по существующему ключу не затирает данные, а добавляет новую версию; удаление ставит delete-marker. Прежние версии остаются и восстанавливаются — это страхует от случайной перезаписи и удаления, но за хранение всех версий надо платить и чистить их lifecycle-правилами.

дальше

Теорию прочитали. Навык ставится повторением

В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.