MAATRIX / Блог / Объектное хранилище у себя вместо зарубежного S3: как переехать без потерь

Объектное хранилище у себя вместо зарубежного S3: как переехать без потерь

MAATRIX

Зарубежное объектное хранилище работало годами без вопросов — пока не появился повод для беспокойства: карта для оплаты может отвалиться в любой момент, провайдер может ограничить работу с аккаунтами из России, а курс и комиссии на конвертацию делают счёт непредсказуемым. Переносить продакшн-хранилище страшно — кажется, что это неделя даунтайма и переписывание половины бэкенда. На практике, если хранилище было S3-совместимым, миграция сводится к смене одного параметра в конфиге и аккуратному плану переноса данных. Разберём, как это сделать, не положив сервис.

Почему self-hosted и обязательно с S3-совместимым API

Первое решение, которое определяет всё остальное: новое хранилище должно говорить на том же языке, что и старое. S3 — это не бренд Amazon, а протокол: HTTP-запросы PUT/GET/DELETE, подпись AWS Signature v4, bucket'ы, multipart upload, presigned URL. Если ваше приложение уже работает с S3-совместимым API — через boto3, aws-sdk-go, MinIO-клиент или просто прямые HTTP-запросы — то при переезде на другое S3-совместимое хранилище меняется буквально один параметр: endpoint_url. Иногда ещё region и флаг path-style вместо virtual-hosted-style. Ключи доступа, логика загрузки, обработка ошибок — всё остаётся как есть. Мы отдельно разбирали, зачем вообще поднимать S3-совместимое хранилище у себя и на чём — если ещё не определились с самой идеей, посмотрите статью про S3-совместимое хранилище у себя.

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

  • Multipart upload — используется ли для больших файлов, и с каким минимальным размером части.
  • Presigned URL — генерирует ли бэкенд временные ссылки на скачивание/загрузку напрямую из фронтенда.
  • Версионирование объектов — включено ли на бакетах, и полагается ли логика приложения на историю версий.
  • Lifecycle-правила — есть ли автоматическое удаление или перенос в холодный класс хранения по возрасту объекта.
  • CORS-настройки — если браузер обращается к хранилищу напрямую, а не через ваш бэкенд.
  • Провайдер-специфичные фичи — S3 Select, интеграция с KMS конкретного облака, теги для биллинга. Это то, что при переезде на self-hosted решение либо не воспроизводится один в один, либо требует отдельной настройки.

Если список выше — пустой или почти пустой (просто кладём и забираем файлы по ключу), миграция будет максимально прямолинейной. Если список длинный — закладывайте время на проверку каждого пункта на новом стеке до, а не после переключения продакшна.

Какое ПО выбрать: MinIO, Garage, SeaweedFS

Все три — открытые S3-совместимые серверы, но заточены под разные сценарии, и выбор здесь влияет на то, как дальше будет вести себя ваш конкретный набор данных.

РешениеСильная сторонаКогда не подходит
MinIOЗрелость, admin-консоль, erasure coding, широкая совместимость с S3 APIТребует несколько дисков/узлов для полноценной отказоустойчивости
GarageРассчитан на геораспределённые узлы со слабым и нестабильным каналом между нимиМеньше готовых интеграций и инструментов вокруг, чем у MinIO
SeaweedFSЭффективен на очень большом количестве мелких файлов (миллионы объектов)Более сложная архитектура (master + volume + filer), выше порог входа

Для типичного случая «было облако, приложение кладёт фото/документы/бэкапы через S3 API» чаще всего разумный выбор — MinIO: он ближе всего по поведению к тому, к чему приложение уже привыкло, и проще в первичной настройке. Если у вас несколько площадок в разных городах или странах со слабым каналом между ними — стоит присмотреться к Garage, он для этого и проектировался. Если основная боль — не объём в байтах, а именно количество файлов (миллионы мелких превью, логов, документов), сравнение стоит делать в пользу SeaweedFS. Более подробное сравнение Garage и SeaweedFS с конкретными сценариями — в статье Garage или SeaweedFS: что выгоднее и когда.

Не пытайтесь заранее угадать «на будущее» — выбирайте под тот профиль нагрузки, который у вас есть сейчас. Миграция между самими self-hosted S3-решениями впоследствии — тоже просто смена endpoint, а не катастрофа.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Требования к серверу: диск, отказоустойчивость, память

Здесь есть развилка, в которой чаще всего ошибаются те, кто переезжает с облака впервые: облачный провайдер брал избыточность на себя и прятал её в цене, а на своём сервере эту избыточность нужно спроектировать самому.

Объём диска. Закладывайте не «текущий объём данных», а текущий объём плюс рост за горизонт планирования (обычно 12–18 месяцев) плюс накладные расходы избыточности. Если используете erasure coding в MinIO (например, схему с 4 дисками, где 2 хранят данные и 2 — чётность), полезный объём будет заметно меньше суммарной ёмкости дисков — точная доля зависит от выбранной схемы EC, считайте её отдельно под свою конфигурацию, а не по памяти.

Тип диска. Для горячих данных (регулярное чтение/запись из приложения) — NVMe или как минимум SSD: задержка на объектных операциях у HDD заметно выше, особенно при большом количестве параллельных запросов. Для холодного архива, куда пишут и почти не читают, HDD может быть оправданной экономией — но тогда стоит держать это на отдельном пуле, не смешивая с горячими данными на одних и тех же дисках.

RAID и erasure coding — не складывайте их друг на друга. Частая грабля: включить аппаратный/программный RAID под дисками, а поверх — ещё и erasure coding в MinIO. Получаете двойную избыточность, двойной расход полезного объёма и просадку по производительности без выигрыша в надёжности — MinIO рассчитан на то, что сырые диски отдаются ему напрямую (JBOD), а избыточность обеспечивает сам. Если решение не поддерживает собственную erasure coding (или вы держите один узел с одним диском) — тогда RAID оправдан как единственный уровень защиты от отказа диска. Подробно про уровни RAID, где они нужны и когда не нужны — в статье RAID на сервере: уровни и как выбрать.

Отказоустойчивость на уровне узлов. Один сервер с одним диском — это единая точка отказа: диск умер, хранилище недоступно, пока не восстановите его из бэкапа. Минимально разумная схема для продакшна — несколько узлов (у MinIO обычно фигурирует конфигурация от 4 узлов для полноценного distributed-режима с erasure coding между узлами, а не только внутри одного), либо один надёжный узел с RAID и обязательным вынесенным бэкапом на физически другую машину. Что выбрать, зависит от бюджета и от того, насколько критична доступность именно объектного хранилища для вашего сервиса — это стоит явно проговорить с бизнесом до переезда, а не постфактум.

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

План миграции данных без потери доступности

Сама механика переноса — это не разовое копирование, а несколько проходов с сужающимся окном рассинхронизации.

Шаг 1. Инвентаризация. Соберите список бакетов, объём в байтах, число объектов, включённые политики. Инструмент rclone умеет считать это по обоим хранилищам одинаково:

rclone size old-s3:my-bucket
rclone size new-minio:my-bucket

Шаг 2. Настройка двух remote-подключений. В rclone.conf заводите старое хранилище и новое рядом:

[old-s3]
type = s3
provider = Other
access_key_id = OLD_KEY
secret_access_key = OLD_SECRET
endpoint = s3.old-provider.example.com

[new-minio]
type = s3
provider = Minio
access_key_id = NEW_KEY
secret_access_key = NEW_SECRET
endpoint = https://storage.yourdomain.example

Шаг 3. Первичная объёмная копия — пока старое хранилище продолжает обслуживать продакшн. На больших объёмах один поток rclone не выберет весь канал — распараллеливайте:

rclone sync old-s3:my-bucket new-minio:my-bucket \
  --transfers=32 --checkers=64 \
  --s3-upload-concurrency=8 \
  --progress

Это может занимать часы или дни в зависимости от объёма и канала — не пытайтесь угадать точный срок заранее, лучше замерить скорость на первых 10–15 минутах и экстраполировать. Приложение в это время продолжает писать в старое хранилище как обычно.

Шаг 4. Инкрементальные досинхронизации. Пока идёт или уже завершилась первая объёмная копия, в старом хранилище появляются новые и изменённые объекты. Повторяйте rclone sync — он копирует только дельту, сравнивая по размеру и времени модификации (или чексуммам, если явно указать --checksum):

rclone sync old-s3:my-bucket new-minio:my-bucket --transfers=16

Каждый следующий проход будет заметно быстрее предыдущего, потому что основной объём уже перенесён.

Шаг 5. Окно переключения. Это единственный момент, где нужна короткая пауза записи — но не чтения. Практическая последовательность:

  1. Переводите приложение в режим "только чтение" для операций записи в хранилище (обычно это флаг в конфиге или feature-toggle, специфичный для вашего бэкенда).
  2. Запускаете финальный rclone sync — теперь дельта минимальна, счёт может идти на секунды-минуты, а не часы.
  3. Сверяете количество объектов и суммарный объём на обеих сторонах.
  4. Меняете endpoint_url в конфиге приложения на новое хранилище, перезапускаете сервис.
  5. Делаете тестовую запись и чтение через приложение (не напрямую через rclone) — это проверяет весь путь, включая права доступа и presigned URL, если они используются.
  6. Снимаете режим "только чтение".

Если ваша архитектура это позволяет, можно смягчить окно переключения через недолгий режим dual-write (запись одновременно в оба хранилища на уровне кода приложения) — тогда пауза записи не нужна вообще, но это требует правки кода бэкенда, а не только конфига, и оправдано в основном для сервисов, где даже минутный read-only неприемлем.

Проверка после переезда и отключение старого хранилища

Не спешите удалять данные со старого провайдера сразу после переключения — это тот случай, где неделя-другая избыточности стоит своих денег.

Сверьте целостность не только по количеству файлов, но и по содержимому:

rclone check old-s3:my-bucket new-minio:my-bucket

Учтите нюанс: у мультипарт-загруженных объектов ETag в S3 API не всегда равен обычной MD5-сумме файла — это артефакт того, как считается хэш составных загрузок. Если rclone check ругается на несовпадение чексумм именно для больших файлов, которые заведомо гружены через multipart, — это не обязательно повреждение данных, но проверить стоит выборочно вручную (скачать и сравнить SHA256 файла целиком).

Дальше — функциональная проверка на уровне приложения, а не только файлов: генерация presigned URL, загрузка через веб-интерфейс, если он есть, работа фоновых задач, которые пишут в хранилище (импорт, экспорт, обработка загруженных файлов). Старые presigned URL, выданные ещё старым хранилищем до переключения, работать после отключения провайдера уже не будут — это стоит учесть, если такие ссылки рассылались пользователям и имеют долгий срок жизни: заранее предупредите, что после определённой даты ссылки перестанут открываться, либо перегенерируйте их под новый endpoint.

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

Резервное копирование на новом месте

Здесь есть момент, который часто упускают в спешке миграции: у зарубежного облака резервирование данных было чужой головной болью, спрятанной в цене подписки. На своём сервере эта ответственность полностью переходит к вам — никто не гарантирует «одиннадцать девяток» надёжности по умолчанию.

Базовое правило — бэкап объектного хранилища не должен физически лежать на том же сервере, что и само хранилище. Варианты:

  • Зеркалирование на второй сервер тем же rclone или mc mirror по расписанию (cron или systemd timer), в другой локации или хотя бы на другом физическом узле.
  • Встроенная репликация между сайтами, если решение её поддерживает (у MinIO есть bucket replication между двумя инстансами) — это не замена бэкапу в строгом смысле (случайное удаление реплицируется тоже), но снижает риск потери от отказа железа.
  • Версионирование бакетов защищает от случайной перезаписи или удаления одного объекта, но не от полной потери сервера — это дополнение к бэкапу, а не его замена.

Отдельно закладывайте регулярную проверку восстановления — бэкап, который ни разу не разворачивали обратно, с практической точки зрения не отличается от отсутствия бэкапа. Подробный разбор именно бэкапа MinIO — со схемой репликации, версионированием и сценарием disaster recovery — в статье бэкап и восстановление MinIO.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Нужно ли переписывать код приложения при переезде на self-hosted S3?

В типичном случае — нет, если приложение уже работает через стандартный S3 SDK и не завязано на провайдер-специфичные фичи из списка выше. Меняется endpoint, ключи доступа и, возможно, флаг path-style — остальная логика работы с бакетами не трогается.

Что будет со старыми presigned URL после отключения прежнего провайдера?

Они перестанут работать, как только аккаунт у старого провайдера закрыт или отключён доступ. Если такие ссылки могли быть разосланы пользователям с долгим сроком жизни — предупредите заранее или перегенерируйте их под новый endpoint до отключения старого хранилища.

Сколько времени займёт перенос данных?

Зависит от объёма, числа файлов и пропускной способности канала между старым и новым хранилищем — универсальной цифры нет. Разумный подход: замерить скорость на коротком тестовом прогоне rclone sync и экстраполировать на весь объём, оставив запас на инкрементальные досинхронизации.

Можно ли обойтись вообще без паузы записи при переключении?

Да, через dual-write на уровне кода приложения (запись одновременно в оба хранилища некоторое время), но это требует правок в бэкенде, а не только смены конфига. Для большинства сценариев короткое окно read-only на минуты — более простой и предсказуемый компромисс.

RAID или erasure coding — можно и то, и другое для надёжности?

Не одновременно на одних и тех же дисках — это двойная избыточность, которая съедает полезный объём и снижает производительность без реального выигрыша. Выбирайте один уровень защиты от отказа диска: либо RAID под одиночным узлом, либо erasure coding в distributed-режиме на нескольких узлах с сырыми дисками.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →