Объектное хранилище S3: классы, lifecycle, presigned-URL, надёжность
S3 — плоское объектное хранилище: бакеты, ключи, классы хранения с трейдоффами извлечения/мин. срока, lifecycle-политики, presigned-URL, 11 девяток надёжности (не доступности) и строгая консистентность. Выбирай класс по паттерну доступа, а не по надежде.
Дата-команда переносит пять лет сырых логов событий — 400 ТБ, читаемых пару раз в год для комплаенса — в S3 и оставляет в Standard, потому что «это же просто S3». Месячный счёт за один этот бакет читается как ещё одна ставка в штат. Тогда кто-то пишет lifecycle-правило, сбрасывающее всё старше 90 дней в Glacier Flexible Retrieval, и чувствует себя умником. Через шесть недель аудитору нужен срез прошлогодних данных сейчас, команда запускает массовый restore по миллионам объектов и получает удар дважды: restore идёт часами, а плата за извлечение по центам за ГБ на сотнях терабайт даёт всплеск счёта, который никто не закладывал. Ни первый выбор, ни фикс не были неверны из-за S3. Они были неверны, потому что никто не прочитал паттерн доступа и не подобрал под него класс хранения — единственное решение, которое S3 навязывает тебе и тихо тарифицирует каждый месяц, что ты ошибаешься.
Бакеты, ключи и плоское пространство ключей
S3 — объектное хранилище, не файловая система. Объект — это байты плюс метаданные плюс ключ, и он лежит в бакете — глобально-именованном, привязанном к региону контейнере. Настоящих директорий нет. Ключ logs/2026/06/04/app.log выглядит как путь, но это единая плоская строка; слэши — просто символы. Консоль рисует дерево папок для удобства, разбивая по /, но под капотом есть одно гигантское лексикографическое пространство ключей и ничего больше. Это важно, потому что почти всё, что масштабируется в S3, масштабируется по префиксу — ведущей части ключа, — а не по папке, потому что папок не существует.
Эта плоская модель формирует и производительность. S3 даёт как минимум 3 500 запросов PUT/COPY/POST/DELETE и 5 500 запросов GET/HEAD в секунду на префикс, и число префиксов ничем не ограничено. Так что пропускную способность по запросам ты проектируешь, разнося ключи по префиксам, а не упираешься в фиксированную квоту. Бакет, который гонит каждую запись через один горячий префикс (скажем, ключи, начинающиеся с одной и той же даты), начнёт троттлить с 503 SlowDown задолго до того, как бакет «заполнится», — потому что у бакета нет лимита размера, есть только лимиты запросов на префикс.
# Ключ — это одна плоская строка; «папки» — просто слэши в ней.
aws s3api put-object \
--bucket app-prod-events \
--key "logs/2026/06/04/ingest-7f3a.json.gz" \
--body ingest-7f3a.json.gz \
--storage-class STANDARD
# Листинг по префиксу — это и есть то, что «ls папки» делает под капотом.
aws s3api list-objects-v2 \
--bucket app-prod-events \
--prefix "logs/2026/06/04/" \
--query "Contents[].{Key:Key,Class:StorageClass,Bytes:Size}"С декабря 2020 года S3 также даёт строгую консистентность read-after-write бесплатно, на каждом запросе, в каждом регионе. После успешного PUT — будь то новый объект, перезапись или удаление — любой последующий GET, HEAD или LIST немедленно видит актуальное состояние. Старые оговорки об eventual consistency («сразу после записи можно прочитать устаревший или отсутствующий объект») ушли. Обходные пути read-your-write больше не нужны; если чтение сегодня выглядит устаревшим, баг в твоём коде или слое кэширования, а не в S3.
Классы хранения: трейдофф извлечения против мин. срока
Когда ты кладёшь данные в S3, класс по умолчанию никогда не нейтрален — это тихое биллинговое решение, принятое один раз и тарифицируемое каждый месяц. Прежде чем выбрать первый класс из списка, задай себе вопрос: как часто эти данные будут реально читаться и как быстро они должны возвращаться? Ответ задаёт все трейдоффы ниже.
Каждый объект несёт класс хранения (storage class), и этот единственный атрибут — главный рычаг стоимости. Классы разменивают три вещи: цену хранения за ГБ, латентность извлечения и минимальный срок хранения, за который ты платишь, даже если удалишь раньше. Числа ниже — из документации AWS; долларовые цифры иллюстративны и зависят от региона — всегда сверяйся со страницей цен S3.
S3 Standard — класс по умолчанию: хранится в ≥3 зонах доступности (AZ), доступ за миллисекунды, без минимального срока, без платы за извлечение. Это верный дом для горячих данных и неверный для всего холодного — ты платишь премиальную цену за байты, которые никто не читает.
Standard-IA (Infrequent Access) сохраняет ту же ≥3-AZ устойчивость и доступ за миллисекунды, но режет цену хранения в обмен на плату за извлечение за ГБ и минимальный срок 30 дней. One Zone-IA ещё дешевле, потому что хранит в одной-единственной AZ — тот же дизайн надёжности, но если эта AZ физически утрачена, данные исчезли. Intelligent-Tiering обходит угадывание: за небольшую плату за мониторинг на объект он автоматически перемещает каждый объект между тирами доступа по мере смены паттерна, без платы за извлечение и без минимального срока — безопасный дефолт, когда паттерн действительно неизвестен.
Семейство Glacier — для архивов. Glacier Instant Retrieval сохраняет доступ за миллисекунды (мин. срок 90 дней) для редко читаемых данных, которые всё же нужны быстро. Glacier Flexible Retrieval (мин. 90 дней) и Glacier Deep Archive (мин. 180 дней) — настоящее холодное хранилище: объекты архивированы и недоступны в реальном времени — нужно вызвать RestoreObject и подождать минуты-часы (Flexible) или часы (Deep Archive), прежде чем читать, и сверх того заплатить за извлечение за ГБ. Именно в эту плату за извлечение и латентность и врезалась команда из Hook.
| Класс | AZ | Латентность извлечения | Мин. срок | Плата за извлечение |
|---|---|---|---|---|
| Standard | ≥3 | Миллисекунды | Нет | Нет |
| Standard-IA | ≥3 | Миллисекунды | 30 дней | За ГБ |
| One Zone-IA | 1 | Миллисекунды | 30 дней | За ГБ |
| Intelligent-Tiering | ≥3 | Миллисекунды (активные тиры) | Нет | Нет (плата за мониторинг) |
| Glacier Instant Retrieval | ≥3 | Миллисекунды | 90 дней | За ГБ |
| Glacier Flexible Retrieval | ≥3 | Минуты–часы (restore) | 90 дней | За ГБ |
| Glacier Deep Archive | ≥3 | Часы (restore) | 180 дней | За ГБ |
▸Почему это работает
Надёжность (durability) и доступность (availability) — разные числа, и команды их путают. Надёжность — рассчитана на одиннадцать девяток (99,999999999%) во всех классах, даже One Zone-IA — это вероятность, что твои байты выживут: шансы потерять объект настолько малы, что статистически близки к нулю. Доступность — это вероятность, что ты сможешь достучаться до объекта прямо сейчас, и она различается по классам (S3 Standard целится в 99,99%, Standard-IA — 99,9%, One Zone-IA — 99,5%). Так что One Zone-IA так же надёжен, как Standard-IA на бумаге — пока единственная AZ, где он лежит, не разрушена физически, после чего надёжность перестаёт иметь значение и ты просто потерял данные. Одиннадцать девяток защищают от отказа дисков и устройств между AZ; они не защищают One Zone-IA от потери его единственной AZ и никогда не защищают тебя от собственного DeleteObject, плохого lifecycle-правила или ransomware. Надёжность — это не бэкап.
Lifecycle-политики и presigned-URL
Объекты между классами руками перемещают редко. Lifecycle-конфигурация на бакете делает это по расписанию: переводит объекты в более холодный класс через N дней и истекает (удаляет) их через M дней. Так ты кодируешь «горячее месяц, редкое квартал, архив год, исчезает через семь лет» одним правилом, а не cron-задачей.
{
"Rules": [
{
"ID": "events-cooling",
"Filter": { "Prefix": "logs/" },
"Status": "Enabled",
"Transitions": [
{ "Days": 30, "StorageClass": "STANDARD_IA" },
{ "Days": 90, "StorageClass": "GLACIER" },
{ "Days": 365, "StorageClass": "DEEP_ARCHIVE" }
],
"Expiration": { "Days": 2555 }
}
]
}Второй рабочий инструмент — presigned-URL. По умолчанию каждый объект приватен — читать его может только владелец. Presigned-URL встраивает ограниченную по времени криптографическую подпись (SigV4), так что любой держатель URL может выполнить одну конкретную операцию — GET для скачивания или PUT для загрузки — пока она не истечёт. Подпись несёт права того, кто сгенерировал URL, поэтому она никогда не даёт доступа больше, чем уже есть у подписавшего. Стандартный паттерн: твой сервер подписывает PUT-URL и отдаёт его браузеру, который загружает файл прямо в S3 — серверы приложения никогда не касаются байтов, так что загрузка на 2 ГБ не занимает процесс приложения и не идёт в твой egress. Срок истечения — это и есть вся модель безопасности: presigned-URL из SDK/CLI может жить до 7 дней (604 800 секунд); консоль ограничивает 12 часами. Подписывай коротко.
import boto3
s3 = boto3.client("s3")
# PUT-URL с ограниченным сроком: отдай его браузеру, чтобы он загружал
# прямо в S3. Истекает через 15 минут; несёт права подписавшего.
upload_url = s3.generate_presigned_url(
ClientMethod="put_object",
Params={"Bucket": "app-prod-uploads", "Key": "user/42/avatar.png"},
ExpiresIn=900, # секунды; макс. 604800 (7 дней) для SigV4
)Логи комплаенса: ~50 ТБ/год, пишутся один раз, почти никогда не читаются, но когда аудитор просит — нужно выдать срез в течение дня-двух (несколько часов ожидания допустимы). Хранение 7 лет. Выбери класс хранения для остывших данных.
Твой бакет троттлит с 503 SlowDown под тяжёлой нагрузкой на запись, хотя бакет вовсе не близок к «заполнению». Самая вероятная причина?
Коллега говорит: «S3 надёжен на одиннадцать девяток, так что бэкапы нам не нужны». Почему это неверно?
- 01Пройди по классам хранения S3 и трём вещам, которые они разменивают, затем дай правило выбора.
- 02Различи надёжность и доступность в S3 и объясни, почему одиннадцать девяток — не бэкап.
S3 — объектное хранилище с единым плоским пространством ключей: ключи лишь выглядят как пути, и всё, что масштабируется, делает это по префиксу, давая примерно 3 500 записей и 5 500 чтений в секунду на префикс без лимита размера бакета и с бесплатной строгой консистентностью read-after-write с декабря 2020 года. Решение, которое S3 навязывает, — класс хранения, главный рычаг стоимости: Standard для горячих данных (≥3 AZ, миллисекунды, без минимума и платы за извлечение); Standard-IA и One Zone-IA для редкого доступа при меньшей цене хранения, но с платой за извлечение за ГБ и минимумом 30 дней, где единственная AZ у One Zone-IA означает, что физическая потеря AZ уничтожает данные; Intelligent-Tiering для авто-перемещения объектов без платы за извлечение и минимума, когда паттерн неизвестен; и семейство Glacier для архивов — Instant Retrieval сохраняет доступ за миллисекунды (минимум 90 дней), тогда как Flexible Retrieval (минимум 90 дней, restore за минуты-часы) и Deep Archive (минимум 180 дней, restore за часы) — настоящее холодное хранилище с платой за извлечение за ГБ, которая подстерегает команды, архивирующие данные, что позже понадобятся быстро. Lifecycle-конфигурации переводят и истекают объекты по расписанию, так что остывание кодируется одним правилом; presigned-URL отдают браузеру подписанный GET или PUT с ограниченным сроком (до 7 дней), чтобы загрузки и скачивания обходили твои серверы целиком. И надёжность — не доступность и не бэкап: одиннадцать девяток значат, что байты выживут при аппаратном отказе, но это никогда не защищает от твоих удалений, плохого lifecycle-правила, ransomware или — для One Zone-IA — потери единственной AZ, где лежит единственная копия. Весь навык — сначала прочитать паттерн доступа и дать ему выбрать класс, потому что S3 тарифицирует тебя каждый месяц, что ты угадываешь неверно. Теперь, когда встретишь неожиданно большой счёт за S3 или всплеск платы за извлечение, первый вопрос — в каком классе хранения лежат данные и совпадает ли реальный паттерн доступа с этим выбором.
Практика
Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.
Что-то непонятно?
Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.
Примени это
Примени этот урок в реальном проекте.