Object storage кажется «положил и забыл», но в production без операционной дисциплины bucket-ы превращаются в десятки терабайт мусора с непонятной стоимостью. Эта статья — про backup-стратегии, replication, costs и мониторинг.
S3 как backup-target
Универсальный backup-целевик: PostgreSQL дампы, MongoDB snapshots, Elasticsearch snapshots, файлы конфигурации, секреты (зашифрованные через KMS). Преимущества S3 как backup'а:
- Durability 99.999999999% (11 девяток) — практически невозможно потерять данные при правильно настроенном versioning + replication.
- Cheaper storage classes — Glacier Deep Archive стоит ~$1/TB/месяц.
- Versioning даёт защиту от ransomware и accidental delete.
- Replication в другой регион/account для disaster recovery.
Шаблонная архитектура backup'ов:
production environment
├── PostgreSQL ─── pg_dump --format=custom ─→ s3://backup-bucket/pg/
├── MongoDB ──── mongodump ──→ s3://backup-bucket/mongo/
├── Elasticsearch ─── snapshot API ──→ s3://backup-bucket/es/
└── приложение ── /export/* ──→ s3://backup-bucket/app/
s3://backup-bucket
├── versioning enabled
├── lifecycle:
│ ├── delete non-current versions after 90 days
│ └── transition to GLACIER after 30 days
├── replication → s3://backup-bucket-dr-region (другой регион/account)
└── access policy: только write от production, read от operations
Backup сам S3
Что если потеряется bucket? AWS даёт 11 девяток durability, но ошибка человека — главный риск (случайно удалили bucket, скомпрометирована учётка).
Cross-region replication (CRR) — настройка на bucket-level:
{
"Role": "arn:aws:iam::ACCOUNT:role/replication-role",
"Rules": [{
"Status": "Enabled",
"Destination": {
"Bucket": "arn:aws:s3:::backup-dr-bucket",
"StorageClass": "STANDARD_IA"
},
"DeleteMarkerReplication": { "Status": "Enabled" }
}]
}
Каждый PUT в source-bucket асинхронно реплицируется в destination в другом регионе (или том же — Same-Region Replication, SRR). Реализуется AWS за секунды-минуты.
Replication не реплицирует ранее существовавшие объекты — только новые. Для bulk-replication существующих: aws s3 sync или S3 Batch Replication.
Версионирование + MFA Delete
На критичных backup-bucket'ах включить MFA Delete:
aws s3api put-bucket-versioning \
--bucket backup-bucket \
--versioning-configuration Status=Enabled,MFADelete=Enabled \
--mfa "arn:aws:iam::ACCOUNT:mfa/user 123456"
Удаление объектов теперь требует MFA-токен root-аккаунта. Скомпрометированная учётка обычного пользователя не сможет уничтожить backup.
Lifecycle policies — детально
Уже видели в fundamentals. Здесь — типичные политики на bucket-ы разного назначения:
User-uploaded content
- Filter: prefix "tmp/"
Expiration: 7 days # незавершённые загрузки
- Filter: prefix "users/"
NoncurrentVersionExpiration: 30 days # старые версии аватарок etc.
AbortIncompleteMultipartUpload: 7 days
Logs / audit trails
- Filter: prefix "audit/"
Transitions:
- 30 days → STANDARD_IA
- 90 days → GLACIER_FLEXIBLE
- 365 days → DEEP_ARCHIVE
Expiration: 2555 days # 7 лет для compliance
Backup bucket
- Filter: prefix "pg/"
Transitions:
- 7 days → STANDARD_IA # быстрый restore первой недели
- 30 days → GLACIER_INSTANT # доступ в минуты
- 90 days → DEEP_ARCHIVE # компромисс по retention
Expiration: 365 days
- NoncurrentVersionExpiration: 30 days
- AbortIncompleteMultipartUpload: 1 day
Costs — три источника затрат
AWS S3 биллится за три вещи:
1. Storage (хранение)
Платится per GB-month. Класс хранения определяет цену:
| Класс | $/GB/месяц (us-east-1, грубо) | Применение |
|---|---|---|
| Standard | $0.023 | Активные данные |
| Standard-IA | $0.0125 | Backup, доступ раз в месяц |
| Glacier Instant | $0.004 | Архив с возможным быстрым доступом |
| Glacier Flexible | $0.0036 | Compliance, доступ часами |
| Deep Archive | $0.00099 | Холодный архив, доступ сутками |
100 TB на Standard = ~$2300/месяц. На Deep Archive — ~$100/месяц.
2. Requests (запросы)
PUT/COPY/POST/LIST: ~$0.005 per 1000 requests на Standard. GET/SELECT: ~$0.0004 per 1000 requests на Standard.
Для большинства приложений это копейки. НО: на bucket'е с миллионами мелких файлов и активным listing'ом — может стать заметно. 1M запросов LIST в день = ~$5/день = $150/месяц.
Антипаттерн: писать миллион 1-KB файлов вместо одного 1-GB файла. Стоимость хранения та же, но запросы — в миллион раз дороже.
3. Egress (исходящий трафик)
Самый коварный пункт. AWS S3 → интернет: ~$0.09 per GB.
100 TB egress в месяц = $9000. Это часто превышает стоимость самого S3 для public/CDN-bucket'ов.
Решения:
- CloudFront перед S3 — egress через CloudFront дешевле ($0.085/GB) + кэширование на edge.
- S3 Transfer Acceleration — для intercontinental ускоряет, но не экономит.
- VPC Endpoint для трафика из EC2 в том же регионе — бесплатно. Используйте всегда для backend-to-S3 трафика.
Альтернативные провайдеры
| Провайдер | Egress | Особенность |
|---|---|---|
| AWS S3 | $0.09/GB | Стандарт |
| Backblaze B2 | $0.01/GB или бесплатно (Bandwidth Alliance) | Дёшево, S3-API совместим |
| Cloudflare R2 | бесплатно | S3-API, без egress fee — game changer для public content |
| Wasabi | бесплатно (с условиями) | Дешёвое хранение, но request limits |
| Yandex Object Storage | ~$0.005-0.01/GB | Российская юрисдикция |
Для public-storage с большим egress — Cloudflare R2 часто дешевле AWS S3 в десятки раз. API совместим, переход через endpointOverride в SDK.
Мониторинг
CloudWatch metrics
S3 экспортирует в CloudWatch автоматически (на AWS):
| Metric | Что значит | Алерт |
|---|---|---|
BucketSizeBytes | Размер bucket'а (раз в день) | Внезапный спайк — что-то льётся |
NumberOfObjects | Число объектов (раз в день) | Спайк — массовая загрузка |
AllRequests / GetRequests / PutRequests | Число запросов | Внезапный рост — DDOS / клиент в цикле |
4xxErrors / 5xxErrors | Ошибки | > 0.1% — проблема |
FirstByteLatency / TotalRequestLatency | Latency | Растёт — нагрузка / region issue |
BytesDownloaded / BytesUploaded | Трафик | Базовая метрика стоимости egress |
Access logs
Server access logging — каждый запрос пишется в текстовый файл в другой bucket:
aws s3api put-bucket-logging --bucket production-bucket \
--bucket-logging-status file://logging.json
{
"LoggingEnabled": {
"TargetBucket": "audit-bucket",
"TargetPrefix": "logs/production-bucket/"
}
}
Формат — IP, время, action, key, status, размер, latency, userAgent.
Альтернатива (с большей задержкой, но JSON): CloudTrail data events для S3.
Inventory reports
S3 Inventory — ежедневный (или еженедельный) отчёт со списком всех объектов bucket'а: .csv.gz или .parquet в указанный bucket. Колонки: key, size, storage_class, last_modified, etag, version_id, encryption_status, и т.д.
Полезно для:
- Проверка lifecycle (что лежит в каждом классе).
- Подсчёт сирот (объекты без записи в БД).
- Audit storage usage по префиксам.
Бесплатно (только storage отчёта).
Типичные инциденты
1. Утёкший AccessKey → удаление содержимого
Сценарий: компрометирована учётка с правами s3:DeleteObject. Атакующий удалил всё.
Защита:
- Versioning включён → данные не удалены физически, только delete-marker'ы. Восстановление через
aws s3api list-object-versions+ восстановление каждой версии. - MFA Delete — атакующему нужен MFA-токен root-аккаунта, что блокирует массовое удаление.
- Object Lock в режиме WORM (write-once-read-many) — для compliance-bucket'ов делает удаление невозможным даже для admin'а.
- Cross-region/account replication — DR-копия в другом аккаунте недостижима с скомпрометированной production-учётки.
2. Объект ушёл в Glacier Deep Archive по ошибке
Lifecycle policy случайно применилась к horячему prefix'у. Объекты — в Deep Archive, чтение занимает 12 часов и стоит $$$.
Защита:
- Lifecycle policy с осторожными фильтрами — всегда тестировать на маленьком префиксе.
- MFA Delete не помогает — переход в Glacier не считается удалением.
- Восстановление:
restore-objectзапрос, ожидание, потом copy в Standard. Минимум 12 часов, оплата за retrieval.
3. Bucket стал public случайно
Чьи-то правки в bucket policy → весь bucket доступен миру. Утечка persistent данных, плюс возможный massive egress на стоимость в десятки тысяч долларов.
Защита:
Block Public Accessна уровне аккаунта — глобальный switch, который не даёт сделать bucket public, даже если кто-то изменил policy. Включить на root-account уровне всегда.- Macie / cloud security tools — автоматически детектят public bucket'ы и предупреждают.
4. Тысячи мелких объектов → биллинг шок
Команда логирует каждое событие отдельным PUT в S3. Через месяц — миллионы файлов, бил по requests.
Защита:
- Aggregation — складывать события в локальный файл, периодически (раз в N минут или N MB) гнать одним PUT.
- Использовать Kafka / Kinesis между приложением и S3 (Firehose батчит автоматически).
- CloudWatch metric
NumberOfObjects— рост на тысячи в день — повод проверить.
Чек-лист production-bucket'а
Минимальный набор настроек, который должен быть на каждом prod-bucket'е:
- ☐ Block Public Access включён (на уровне аккаунта тоже).
- ☐ Versioning включён.
- ☐ SSE-S3 или SSE-KMS (default с 2023 для новых, проверить старые).
- ☐ Lifecycle policy настроен:
- Abort incomplete multipart uploads после 7 дней.
- NonCurrentVersionExpiration (старые версии не копятся бесконечно).
- Transition в colder classes если применимо.
- ☐ CloudWatch alarm на резкий рост размера / числа объектов / 5xx errors.
- ☐ Access logging или CloudTrail data events — для audit.
- ☐ Cross-region replication для критичных bucket'ов (backup, compliance).
- ☐ VPC endpoint для трафика из EC2/EKS — экономия egress.
- ☐ MFA Delete на backup/compliance bucket'ах.
- ☐ IAM policy — минимальные права.
s3:*— антипаттерн.
Что почитать дальше
- Fundamentals — модель S3.
- Spring + AWS SDK v2 — клиентский код.
- Elasticsearch operations — S3 как backup-target для ES snapshots.
- AWS Well-Architected: S3.