← назад к разделу

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.0125Backup, доступ раз в месяц
Glacier Instant$0.004Архив с возможным быстрым доступом
Glacier Flexible$0.0036Compliance, доступ часами
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 / TotalRequestLatencyLatencyРастёт — нагрузка / 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.