Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → Версии объектов и резервное копирование хранилища

Версионирование объектов: защита от удаления и перезаписи

Версионирование S3: идентификаторы версий, маркеры удаления, неактуальные версии, репликация между бакетами и контроль затрат.

Прямой ответ

Версионирование бакета сохраняет каждую версию объекта вместо замены. Перезапись создаёт новую версию, а прежняя остаётся доступной по идентификатору. Удаление не уничтожает данные, а добавляет маркер удаления — специальную версию, означающую «объект удалён».

Поведение:

Действие Без версионирования С версионированием
Запись по существующему ключу Данные заменяются Создаётся новая версия, старая сохраняется
Удаление Данные уничтожаются Добавляется маркер удаления
Чтение Текущее содержимое Текущая версия, если не указан идентификатор
Восстановление Невозможно Удаление маркера или копирование нужной версии
import boto3
s3 = boto3.client("s3")

# список версий объекта
resp = s3.list_object_versions(Bucket="docs", Prefix="contract.pdf")
for v in resp.get("Versions", []):
    print(v["VersionId"], v["LastModified"], v["Size"])

# восстановление: читаем конкретную версию
obj = s3.get_object(Bucket="docs", Key="contract.pdf",
                    VersionId="3HL4kqtJlcpXrof3W3Zz4YBdvdz2FJ9n")

Восстановление после ошибочного удаления выполняется удалением маркера:

aws s3api delete-object --bucket docs --key contract.pdf \
  --version-id "0Byf7PhYiOWL2xD87gmdUwsR1lUp0XTk"

Важно понимать границы механизма. Версионирование не заменяет резервное копирование. Оно защищает от случайной перезаписи и удаления, но не от удаления самого бакета, от вредоносного шифрования данных и от ошибок в коде, который массово перезаписывает объекты. Для этих сценариев нужна репликация в другой бакет или регион.

Вторая особенность — стоимость. Хранятся и оплачиваются все версии. Бакет с активной перезаписью мелких объектов растёт заметно быстрее, чем объём полезных данных.

Практика: настройка и контроль

1. Включайте версионирование до появления данных. Включение на заполненном бакете не создаёт версии существующих объектов: они получают идентификатор null, и дальнейшее поведение отличается.

2. Настройте правило для неактуальных версий. Без него старые версии накапливаются навсегда:

<Rule>
  <ID>expire-noncurrent</ID>
  <Status>Enabled</Status>
  <NoncurrentVersionExpiration>
    <NoncurrentDays>30</NoncurrentDays>
  </NoncurrentVersionExpiration>
</Rule>

Срок выбирают исходя из того, за какое время обнаруживается ошибочная перезапись. Тридцать дней — разумный компромисс; о правилах подробнее в статье про жизненный цикл.

3. Удаляйте висячие маркеры удаления. Маркер, под которым не осталось версий, бесполезен и занимает место в списке. Правило ExpiredObjectDeleteMarker убирает их автоматически.

4. Используйте репликацию для защиты от потери бакета. Репликация копирует новые объекты и версии в целевой бакет, в том числе в другой регион:

aws s3api put-bucket-replication --bucket docs --replication-configuration '{
  "Role": "arn:aws:iam::123456789012:role/s3-replication",
  "Rules": [{"ID":"all","Status":"Enabled","Destination":
    {"Bucket":"arn:aws:s3:::docs-dr"},"DeleteMarkerReplication":{"Status":"enabled"},
    "Prefix":""}]}'

Репликация асинхронна, поэтому она не даёт нулевой точки восстановления.

5. Защищайте критичные версии от удаления. Object Lock запрещает удаление версии в течение заданного срока, что защищает от вредоносного или ошибочного массового удаления.

6. Разделяйте версионирование данных и версионирование артефактов. Для сборок и релизов версионирование задаётся именами и тегами, а не механизмом бакета — см. статью про артефакты сборки.

7. Ограничивайте права на удаление версий. Возможность удалить конкретную версию должна быть у меньшего числа ролей, чем запись объекта.

Рекомендации:

  1. Мониторьте объём версий. Метрика числа версий на объект показывает, что срок хранения неактуальных версий слишком велик.
  2. Тестируйте восстановление. Проверка, что конкретную версию можно прочитать и вернуть, важнее факта включения версионирования.
  3. Не используйте версионирование как замену миграции схемы. Хранение множества версий файла не решает задачу совместимости форматов.
  4. Учитывайте задержку репликации. При аварии часть последних записей может отсутствовать в целевом бакете.
  5. Документируйте процедуру восстановления. В момент инцидента искать идентификатор версии и команду некогда.

Практический сценарий: скрипт перезаписал тысячу документов пустыми файлами

Контекст: задача миграции записывала обновлённые документы в бакет. Из-за ошибки в пути она записала пустые файлы поверх существующих.

  1. Обнаружение. Пользователи сообщили, что документы открываются пустыми. Проверка показала нулевой размер у 1 240 объектов.
  2. Диагностика. Бакет был версионируемым, поэтому list_object_versions вернул предыдущие версии с корректным размером и датой до запуска задачи.
  3. Причина. Задача формировала ключ из поля, которое оказалось пустым для части записей, и записывала результат без проверки. Предварительного прогона на выборке не было.
  4. Действия. (а) Восстановили объекты копированием предыдущей версии на текущий ключ, проверив размер после каждой операции; (б) удалили созданные маркеры и пустые версии по правилам жизненного цикла; (в) добавили в задачу проверку непустого результата и отказ от записи при нулевом размере; (г) ввели правило NoncurrentVersionExpiration на 30 дней, поскольку ранее оно отсутствовало и объём рос; (д) добавили тестовый прогон на копии бакета перед изменением данных.
  5. Результат. Данные восстановлены за 25 минут; повторное выполнение задачи с ошибкой больше не приводит к потере, поскольку прежние версии сохраняются.

Вывод: версионирование превращает катастрофическую перезапись в обратимую операцию, но только если оно включено заранее и настроены сроки хранения версий. Процедура восстановления должна быть проверена до инцидента.

FAQ

Можно ли отключить версионирование полностью? Можно перевести бакет в состояние suspended, но существующие версии останутся. Полное удаление требует очистки всех версий вручную.

Что такое версия null? Это версия объекта, существовавшего до включения версионирования. Она одна на ключ и при перезаписи заменяется, поэтому такие объекты защищены слабее.

Увеличивает ли версионирование стоимость чтения? Нет, чтение текущей версии не отличается от обычного. Расходы растут за счёт хранения дополнительных версий.

Заменяет ли версионирование резервные копии? Нет. Оно защищает от перезаписи и удаления, но не от потери бакета, региона или вредоносного удаления всех версий. Нужны репликация и отдельная копия.

Источники: AWS S3 docs (Versioning, Replication), MinIO docs — ссылки в шапке.