Вход на сайт

Просмотр новости

Найдите то, что Вас интересует

Переезд S3 без простоя и без привязки к одному облаку: rclone union + serve s3 на практике

Дата публикации: 16-10-2026 04:25:56

«Три зоны доступности» внутри одного облака не спасают, когда отказывает само облако. Собираем S3, который переживает отказ провайдера: один endpoint для приложения, за ним несколько облаков, переезд без простоя и без правок в коде. Всё на rclone — union, combine и serve s3. Два режима: старое облако работает или после аварии отдаёт данные только на чтение. Читать далее

Основное содержимое страницы с новостью.

Уровень сложностиСредний

Время на прочтение5 мин

Охват и читатели7.3K

Туториал

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

Решение целиком собрано из rclone. Его обычно знают как «rsync для облаков»: rclone copy и rclone sync между диском и бакетом. Но у rclone есть ещё два слоя, о которых вспоминают редко.

Первый — виртуальные бэкенды. Это remote’ы, которые сами ничего не хранят, а собираются из других: union склеивает несколько хранилищ в одно, combine раскладывает разные хранилища по каталогам, а crypt, chunker и compress шифруют, режут и сжимают на лету. Из них, как из конструктора, складывается одно логическое хранилище поверх любых из примерно семидесяти поддерживаемых бэкендов: S3 любого провайдера, SFTP, WebDAV, локального диска.

Второй — rclone serve. Любой remote, включая собранный из виртуальных, rclone умеет отдавать наружу как сервер: по HTTP, WebDAV, FTP, SFTP, NFS, для restic — и по S3 API. rclone serve s3 превращает rclone в S3-совместимый прокси: приложение ходит в него обычным SDK и не знает, что за ним несколько провайдеров.

Отсюда схема: один S3-endpoint для приложения, за ним несколько провайдеров. Конфигурация у обеих ситуаций общая, различаются состав union и перенос данных.

Схема
[webshield]
type = s3
provider = Other
endpoint = https://s3.webshield.pro
force_path_style = true
no_check_bucket = true
access_key_id = ...
secret_access_key = ...

[sel]
type = s3
provider = Selectel
endpoint = https://s3.ru-1.storage.selcloud.ru
region = ru-1
access_key_id = ...
secret_access_key = ...

[old]
type = s3
provider = Other
endpoint = https://storage.old-cloud.example
access_key_id = ...
secret_access_key = ...

Имена бакетов у провайдеров разные, поэтому у каждого сначала собирается одинаковое дерево через combine:

[webshield_all]
type = combine
upstreams = media=webshield:u42-media dumps=webshield:u42-dumps

[sel_all]
type = combine
upstreams = media=sel:acme-media dumps=sel:acme-dumps

[old_all]
type = combine
upstreams = media=old:media dumps=old:dumps

А поверх — union, который делает из нескольких деревьев одно. В обычном режиме это текущий провайдер и новый, оба полноправные:

[s3all]
type = union
upstreams = old_all: webshield_all:
create_policy = all
action_policy = all
search_policy = ff

В аварийном старое облако уходит последним и только на чтение, а писать приходится в два новых провайдера:

upstreams = webshield_all: sel_all: old_all::ro

create_policy = all и action_policy = all пишут и удаляют во всех upstream’ах, кроме помеченного :ro. search_policy = ff читает с первого, где объект нашёлся: порядок в upstreams — это приоритет.

Порядок слоёв важен. Первая версия была наоборот — union для каждого бакета и combine сверху. Она работала, пока не понадобилось перезаписать объект, который ещё лежал только в старом облаке: новая версия уезжала по неверному пути, а читалась старая.

Приложение не меняется

rclone serve s3 поднимает поверх s3all: обычный S3 API. Каталоги верхнего уровня — media и dumps — становятся бакетами с прежними именами. Прокси запускается на каждой машине с приложением и слушает только localhost: у каждого сервера свой экземпляр, поэтому ни балансировщик, ни TLS не нужны, а сам прокси не становится единой точкой отказа.

rclone serve s3 s3all: \
  --addr 127.0.0.1:8333 \
  --auth-key "$APP_ACCESS_KEY,$APP_SECRET_KEY" \
  --contimeout 3s --timeout 30s --low-level-retries 2 \
  --dir-cache-time 5s

У приложения своя пара ключей, ключи провайдеров есть только в rclone.conf. Таймауты обязательны: с умолчаниями rclone повторяет запросы к упавшему провайдеру минутами, и прокси на это время зависает.

--dir-cache-time важен не меньше. Прокси кеширует каталоги, по умолчанию на 5 минут, и для уже найденного объекта помнит, у какого провайдера он лежит. Если упал именно этот провайдер, чтение не переключается на второй, а обрывается ошибкой — до конца кеша. С 5 секундами первое чтение после отказа занимает несколько секунд, дальше всё идёт со второго провайдера.

В приложении меняются адрес и ключи. Если адрес берётся из окружения, достаточно поменять значение — AWS_ENDPOINT_URL читают свежие boto3, AWS CLI v2, aws-sdk-js v3 и Go SDK v2:

AWS_ENDPOINT_URL=http://127.0.0.1:8333
AWS_ACCESS_KEY_ID=$APP_ACCESS_KEY
AWS_SECRET_ACCESS_KEY=$APP_SECRET_KEY

rclone — не ниже 1.75.2: механизм serve достаточно новый и сейчас активно дорабатывается.

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

Перенос данных: обычный режим

Когда текущий провайдер работает и открыт на запись, всё просто. Приложение через union пишет и удаляет у обоих, поэтому обычный rclone copy от старого к новому ничего не откатит и не вернёт удалённое — повторять его можно сколько угодно:

rclone copy old:media webshield:u42-media -M --transfers 16
rclone copy old:dumps webshield:u42-dumps -M
rclone check old:media webshield:u42-media

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

Перенос данных: аварийный режим

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

Поэтому копировали не всё подряд, а по списку живых ключей из базы приложения — удалённых в нём нет:

psql -At -c "select storage_key from attachments" > keys.txt

rclone copy old:media webshield:u42-media \
  --files-from keys.txt --no-traverse --ignore-existing \
  --transfers 8 --checkers 16 --tpslimit 20 \
  --retries 10 --low-level-retries 20 \
  -M --log-file copy.log

rclone copy webshield:u42-media sel:acme-media \
  --files-from keys.txt --no-traverse --ignore-existing -M --transfers 32

Дампы базы в приложении никто не удаляет и не перезаписывает, их копировали целиком теми же двумя шагами: old:dumps → webshield:u42-dumps → sel:acme-dumps с --ignore-existing.

--ignore-existing не трогает то, что у приёмника уже есть: если файл там есть, значит, его записало приложение, и эта версия новее. --files-from с --no-traverse к тому же избавляет от листинга медленного источника. Копировать в s3all: нельзя: union найдёт каждый объект в старом облаке и решит, что копировать нечего. Поэтому сначала копия к одному провайдеру, а уже от него — ко второму: медленный источник читается один раз.

--tpslimit ограничивает число запросов в секунду: старое облако отвечало на всплески ошибкой SlowDown. -M переносит Cache-Control и Content-Disposition — без него Content-Type rclone сохраняет, а остальные заголовки теряются. Файлы, которых нет в старом облаке, rclone пропускает молча и с нулевым кодом выхода, поэтому потери считали отдельно: список ключей против rclone lsf -R приёмника.

Когда всё скопировано, old_all::ro убрали из upstreams и перезапустили прокси. Затем сверили провайдеров между собой (rclone check webshield:u42-media sel:acme-media) и убрали «сирот» — файлы, которые пользователи удалили, пока шло копирование. Их нет в свежей выгрузке из базы, а --min-age не даёт задеть только что загруженные, которые в базу ещё не попали:

psql -At -c "select storage_key from attachments" | sort > live.txt
rclone lsf -R --files-only --min-age 1h webshield:u42-media | sort | comm -23 - live.txt > orphans.txt
rclone delete webshield:u42-media --files-from orphans.txt
rclone delete sel:acme-media --files-from orphans.txt

Чего схема не умеет:

  • ACL, теги, retention и политики бакетов — serve s3 поддерживает только объекты, листинг, multipart и копирование;

  • метаданные при записи через прокси теряются, Content-Type угадывается по расширению;

  • ссылки для браузера через локальный прокси не работают — раздача клиентам остаётся задачей CDN;

  • строгой консистентности нет: сбой посреди записи даёт расхождение до сверки.

Для медиа, документов, артефактов и бэкапов схема подходит. Для частых перезаписей и нагрузки, похожей на базу данных — нет.

Схожие новости

#Наименование новостиТональностьИнформативностьДата публикации
1Один адрес на все хранилища, или как я перестал бояться переездов S305.318-10-2026
2Синхронизация объектов в S3‑хранилище с помощью MinIO CLI0707-07-2026
3S3 в инфраструктуре: где объектное хранилище помогает, а где не заменит файловую систему04.8518-08-2026
4Когда Docker Compose уже мало, а Kubernetes еще слишком много: знакомство с Uncloud. Часть 1010.4216-10-2026
5Как я выгружал 1,8 TB с Яндекс Диска после аварии в дата-центрах012.1417-10-2026
6Отказоустойчивость в мультиклауде: архитектура и реальные кейсы010.4217-09-2026
7Разворачиваем MiniMax-M2.7 на GPU-инфраструктуре с поддержкой S3011.9522-07-2026
8Самохостинг 10 ТБ на ноутбуке, свой сервер вместо облака, личные сайты и сисопки011.4214-10-2026
9Рейтинги облачных хранилищ для бизнеса в России в 2026 году012.4612-10-2026

Классификация: Пресс-релизы. Схожих патентов: 0. Схожих новостей: 9. Тональность: 0. Информативность: 6.03. Источник: habr.com.