Привет, Хабр. Меня зовут Ори Брук, я ведущий инженер в департаменте разработки объектных хранилищ YADRO. Раньше мы не писали о TATLIN.OBJECT, нашей децентрализованной системе хранения данных (СХД). Исправляемся, ведь у нас есть повод — релиз новой функциональности S3-зеркалирования. Она позволяет бесшовно переносить данные из S3-совместимого хранилища MinIO в нашу СХД. Впрочем, функция может работать с любым S3-совместимым хранилищем в качестве источника данных в рамках поддерживаемых вызовов.

Разберемся, как устроено децентрализованное хранилище, как работает S3 прокси-мигратор, и посмотрим на результаты замеров его производительности на примере MinIO.

Что такое объектное хранилище TATLIN.OBJECT

TATLIN.OBJECT — это программно-аппаратный комплекс с децентрализованным движком хранения данных, который был разработан в YADRO. Децентрализация позволяет масштабировать СХД, добавляя новые узлы хранения в любых локациях. Также она обеспечивает доступ и сохранность данных во многих неприятных сценариях: от отказа одного узла до заметных сбоев интернета. Решение поддерживает протоколы S3, HTTP(S) и gRPC, стандартные Amazon SDK для S3, а также собственные SDK для Go, С#, Python и Java для работы по нативному протоколу gRPC.

Аппаратная платформа

TATLIN.OBJECT работает на базе серверных решений YADRO, таких как VEGMAN. СХД заказчик устанавливает во внутреннем контуре компании (on-premises) и поэтому сохраняет полный контроль над хранящимися данными. 

Пример размещения узлов децентрализованной СХД TATLIN.OBJECT в стойке
Пример размещения узлов децентрализованной СХД TATLIN.OBJECT в стойке

Для запуска TATLIN.OBJECT в компании достаточно всего четырех узлов хранения. Затем систему можно наращивать с кратностью в один узел и вплоть до сотни узлов.

Пример организации кластера из четырех узлов хранения

Состав узла хранения:

  • 2 × CPU x86

  • 256 ГБ RAM

    • Либо 6/12 × NL SAS HDD 16 TБ + 4 × SATA SSD 1,92 TБ (гибридные узлы)

    • Либо 6/12 x SAS SSD 7,68 ТБ (узлы all-SSD)

  • 2 × 10/25 Гбит с Ethernet для внутренней сети

  • 2 × 10/25 Гбит с Ethernet для доступа к данным

  • 1 × 1 Гбит с Ethernet для сети управления

  • 1 × 1 Гбит с Ethernet для локального сервисного доступа

Разберем основные особенность TATLIN.OBJECT с точки зрения ПО — отечественного движка хранения данных, разработанного с нуля. 

Децентрализация

Движок — это децентрализованная распределенная сеть хранения данных, интегрированная с блокчейном: в ней нет единой точки принятия решений, поэтому нет и единой точки отказа. Узлы сети работают по P2P-принципу, и каждый обеспечивает целостность и доступность данных согласно заданной политике.

Система не разделена на множество мелких отдельных хранилищ, а работает как единая глобальная сеть на базе блокчейна. Он служит своего рода децентрализованными «часами» с монотонно возрастающим временем в виде счетчика блока. Время в движке хранения данных дискретно и не зависит от астрономического. 

Блокчейн в системе играет роль распределенной базы данных. Фактически, это хранилище типа «ключ-значение», где смарт-контракты работают как таблицы или хранимые процедуры. Чтобы система работала быстро, обработка и хранение самих объектов (полезной нагрузки) вынесены за пределы блокчейна. В нем мы проводим операции только с конфигурациями компонентов, смарт-контрактами и метаданными о состоянии сети хранения. Если бы мы манипулировали объектами напрямую через блокчейн, то процедура консенсуса занимала бы слишком много времени.

Особенности хранения данных

Как и в других объектных СХД, единицей хранения в TATLIN.OBJECT выступает объект — сами данные и метаданные (системные и пользовательские). Уникальным идентификатором служит хеш объекта — производная от данных и метаданных. 

Как TATLIN.OBJECT сохраняет файлы

В зависимости от размера файла сохранение происходит по одному из трех сценариев:

  • объекты обычного размера записываются без изменений;

  • большие объекты разделяются на несколько объектов меньшего размера;

  • мелкие объекты объединяются в более крупную структуру.

Все объекты хранятся в контейнерах, которые создают пользователи.  У контейнера есть собственные метаданные (атрибуты) и ряд заданных параметров: 

  • политика доступа, определяющая правила доступа к объектам контейнера;

  • политика хранения, определяющая количество копий и местоположение объектов в системе.

Если взять хеш-структуру контейнера, то мы получим его уникальный идентификатор.

Уникальный адрес объекта формируется из связки идентификатора контейнера и самого объекта. То есть в TATLIN.OBJECT используется концепция неизменяемости данных с глобальной CAS-адресацией (Content-Addressable Storage). Вместо пути к файлу или URL адресом служит хеш-сумма комбинации идентификатора объекта и контейнера, в котором он хранится. 

Важно, что архитектура TATLIN.OBJECT децентрализована: все сервисы доступа активны на каждом узле, а данные распределены по кластеру с использованием политик избыточности. Это гарантирует сохранность данных и доступ к ним даже при одновременном отказе нескольких узлов или дисков, а конкретные параметры можно настроить в политике защиты. 

Протоколы TATLIN.OBJECT для общения с внешним миром

Глобальная CAS-адресация хорошо подходит для работы распределенной сети, но внешняя IT-инфраструктура заточена под стандартные сетевые интерфейсы. Поэтому в нашей СХД есть нативный SDK для Go, С#, Python и Java, а также протокольные шлюзы:

  • gRPC — протокол на базе открытой спецификации, предназначенный для создания кастомных интеграций.

  • HTTP(S) — стандартный веб-протокол с поддержкой REST API для автоматизации управления и возможностью прямой потоковой загрузки данных.

  • S3 (AWS S3 API) — для интеграции с S3-совместимыми приложениями.

Как работает S3 прокси-мигратор

При миграции данных из S3-совместимого хранилища в TATLIN.OBJECT ключевую роль играет S3-шлюз, который работает в режиме зеркалирования. В этом сценарии весь трафик S3-запросов перенаправляется через TATLIN.OBJECT. Логика работы шлюза настроена так, чтобы обеспечивать бесшовный доступ к данным. Например, при запросе содержимого бакета система возвращает информацию из целевого хранилища. Если объекта там нет, то запрос автоматически пересылается в зеркалируемое хранилище (хранилище, которое мы копируем). Одновременно с этим удаление объектов происходит синхронно как в целевой среде TATLIN.OBJECT, так и в зеркалируемом хранилище, что предотвращает потерю данных в процессе миграции. Миграция проходит в фоновом режиме.

S3 прокси-мигратор поддерживает пять основных операций:

  • GetObject,

  • PutObject,

  • ListObjects,

  • ListObjectsV2,

  • DeleteObject.

Каждый конкретный случай миграции с MinIO уникален, и специалисты YADRO проводят его оценку, чтобы процесс прошел без проблем. Информация ниже — верхнеуровневое описание работы S3 прокси-мигратора, но не руководство к действию.

GetObject и PutObject

В TATLIN.OBJECT есть S3-шлюз, который конфигурируется и отвечает за доступность по S3-протоколу. После перехода СХД в режим миграции все вызовы по S3-протоколу теперь направляются в S3-шлюз TATLIN.OBJECT, а прямой доступ к зеркалируемому S3-хранилищу блокируется.

Если в TATLIN.OBJECT нет нужного объекта (ошибка 404), то запрос перенаправляется в хранилище MinIO. Найденный объект передается в TATLIN.OBJECT, а уже из него — пользователю. 

Операция PutObject нужна для загрузки нового объекта или перезаписи уже существующего. Если включено версионирование, то будет создана новая версия объекта, которая станет актуальной. 

Под капотом форк open source-утилиты RClone в фоновом режиме запрашивает список объектов в бакетах для копирования из зеркалируемого хранилища. Параметры подключения к каждому хранилищу — S3-credentials (access key и secret key) и адрес endpoint — задаются в конфигурационном файле RClone (rclone.conf). Названия бакетов для синхронизации указываются непосредственно при запуске команды rclone.

Для каждого хранилища в конфигурационном файле прописаны свои S3-credentials:

> cat rclone.conf
[minio]
type = s3
provider = Other
access_key_id = w***********T
secret_access_key = Ib**************************************Qs
endpoint = http://localhost:9000


bucket_acl = public-read

[frostfs]
type = s3
provider = Other
access_key_id = 8Y*******************************************************************************************************BC
secret_access_key = 7cb****************************************************************************fc6
endpoint = http://localhost:8089


bucket_acl = public-read

Так в фоновом режиме происходит копирование данных из зеркалируемого S3-хранилища в целевое — TATLIN.OBJECT. В форк RClone мы также планируем в ближайшее время добавить режим клонирования объектов для версионированных бакетов.

ListObjects, ListObjectsV2 и DeleteObject

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

Также предусмотрены операции листинга — в S3-протоколе есть операция ListObjects. Она возвращает данные из TATLIN.OBJECT:

Если нужно получить данные из исходного хранилища, то мы используем операцию ListObjectsV2 из S3-протокола:

С ее помощью мы получаем объект из исходного S3-хранилища, затем конвертируем в формат TATLIN.OBJECT и возвращаем пользователю. 

Как работает S3-зеркалирование

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

s3_mirroring:
  enabled: false
  region: ru
  access_key: k********h
  secret_key: a***********k
  endpoint: https://minio.com
  namespace: root

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

Параллельно нужно запустить утилиту RClone, которая будет переносить данные из S3-хранилища заказчика в TATLIN.OBJECT. Как только все данные перенесены в целевое хранилище — режим совместимости отключается, а заказчик может использовать оборудование зеркалируемого S3-хранилища для других задач.

Как проверить целостность данных при миграции

Проверку можно провести с помощью RClone: 

./rclone-static-v1.69.1+frostfs.9 lsf minio:serv > list.txt
./rclone-static-v1.69.1+frostfs.9 copy minio:serv frostfs:serv --files-from list.txt --ignore-existing
./rclone-static-v1.69.1+frostfs.9 copy minio:serv frostfs:serv --files-from list.txt --ignore-existing -V
./rclone-static-v1.69.1+frostfs.9 copy minio:serv frostfs:serv --files-from list.txt --ignore-existing -P
./rclone-static-v1.69.1+frostfs.9 copy minio:serv frostfs:serv --files-from list.txt --ignore-existing -P --no-check-dest

Для миграции в TATLIN.OBJECT нужно заранее создать бакет, куда будут копироваться данные из бакета зеркалируемого хранилища (в примере: serv) — утилита работает только с бакетами. В RClone есть команда LSF для получения списка ключей, по которым из бакета запрашиваются данные объектов:

> cat list.txt
sample1
sample2

Полученный список ключей нужно сохранить, чтобы по завершении работы RClone сравнить, все ли ключи бакета из зерклалируемого хранилища совпали с ключами в бакете TATLIN.OBJECT. Если проверить нужно больше, чем один бакет, то пишем скрипт, который идет по списку парных бакетов зеркалируемого и целевого хранилищ и сверяет их идентичность. 

В RClone также есть свои механизмы, которые проверяют, что объект скопирован корректно. 

Совместная работа S3-хранилищ с TATLIN.OBJECT

S3 прокси-мигратор позволяет дополнить уже существующее совместимое S3-хранилище системой хранения данных TATLIN.OBJECT, даже если миграция пока не планируется или совершается поэтапно. Данные будут запрашиваться через TATALIN.OBJECT из остальных хранилищ.

Благодаря S3-зеркалированию новые данные можно сохранять на TATLIN.OBJECT, а старые — получать из уже работающего S3-хранилища. Операцию DeleteObject, то есть удаление объектов из зеркалируемого хранилища, проводить необязательно.

TATLIN.OBJECT, как распределенная система, позволяет сделать логическое разделение и роутинг объектов по пространству имен — настройка режима S3-совместимости и зеркалирования ограничена именно им. Менеджер конфигураций передает указанные пространства имен и соответствующие настройки всем узлам TATLIN.OBJECT и делает их идентичными. 

Если зеркалирование выключено, то объект через S3-шлюз запрашивается только в TATLIN.OBJECT: приходит ответ 200 (найден) или 404 (не найден). 

При включенном зеркалировании и запросе в пространство имен, которое указано в его настройках, запрос при получении от хранилища TATLIN ответа 404 (не найден) перенаправляется в S3-хранилище. Где объект также может быть либо найден, либо нет:

Замеры производительности переноса данных из MinIO в TATLIN.OBJECT

Мы протестировали S3 прокси-мигратор в дата-центре YADRO, поэтому результаты ниже не учитывают сценарии с высокой задержкой (например, Москва — Владивосток), где итоговая скорость будет ограничена параметрами сетевой связности.

Запуск производился на аналогичных платформах для MinIO и TATLIN.OBJECT на базе серверов VEGMAN. 

Для замеров производительности использовались размеры объектов:

  • 8 кБ,

  • 128 кБ,

  • 1 МБ,

  • 32 МБ,

  • 128 МБ.

Тестовые объекты для миграции были расположены:

  • в одном (1b),

  • либо в ста (100b) бакетах.

VUs — количество параллельных потоков нагрузки. Зеркалируемым S3-хранилищем был инстанс MinIO. Мы проводили операции чтения (r) и записи (w) объектов, продолжительность одного теста составляла 5 минут

Для миграции данных с зеркалируемого хранилища мы:

  1. Создали в MinIO тестовые бакеты и записали в них тестовые объекты.

  2. Настроили утилиту RClone на вспомогательном сервере, с которого тоже подается нагрузка.

  3. В TATLIN.OBJECT создали аналогичные MinIO пустые бакеты (с теми же именами и в том же количестве) с политикой хранения по умолчанию.

  4. Запустили клонирование данных через RClone по списку тестируемых бакетов и паралелльно с этим подали на MinIO нагрузку.

Сравнение результатов в одинаковых тестовых сценариях без клонирования данных (run1) и с ним (run2):

Сценарий

Средняя пропускная способность, run1, МиБ/с

Средняя пропускная способность, run2, МиБ/с

Разница, %

w_8k_1b_800VUs

21,81

18,392

15,7

w_128k_1b_600VUs

142,578

126,302

11,4

w_1024k_1b_400VUs

324,544

300,456

7,4

w_32768k_1b_200VUs

1367,188

1269,532

7,1

w_131072k_1b_100VUs

1562,5

1432,292

8,3

r_8k_1b_800VUs

573,893

519,206

9,5

r_128k_1b_600VUs

613,281

580,078

5,4

r_1024k_1b_400VUs

626,302

566,732

9,5

r_32768k_1b_200VUs

526,367

387,044

26,5

r_131072k_1b_100VUs

543,294

318,034

41,5

w_8k_100b_800VUs

13,672

15,462

13,1

w_128k_100b_600VUs

125,651

133,626

6,3

w_1024k_100b_400VUs

279,948

303,874

8,5

w_32768k_100b_200VUs

1204,427

1285,808

6,8

w_131072k_100b_100VUs

1269,531

1416,016

11,5

r_8k_100b_800VUs

777,67

735,189

5,5

r_128k_100b_600VUs

733,724

728,678

0,7

r_1024k_100b_400VUs

515,951

520,02

0,8

r_32768k_100b_200VUc

512,696

525,391

2,5

r_131072k_100b_100VUs

273,438

433,431

58,5

Из таблицы видно, что включение клонирования объектов между системами не приводит к систематическим падениям производительности тестового стенда с MinIO. В большинстве сценариев разница в результатах не превышает 10–15%, что укладывается в рамки естественного разброса данных между итерациями тестов.

Тестирование длилось 9 часов 8 минут. За это время в 1294 бакета склонировано 846 000 объектов пяти разных размеров общим объемом 329 ГБ. За то же время на стенде MinIO выполнено 50,46 млн операций на 27,14 ТБ.

В каждом склонированном бакете объекты одного размера:

Размер объектов в бакете

Количество бакетов

Количество объектов во всех бакетах заданного размера

Передано данных, МБ

8 кБ

519

627592

4903

32 кБ

422

173610

21701

1 МБ

170

38764

38764

32 МБ

132

5203

166496

128 МБ

51

824

105472

Всего:

1294

845993

337336

TATLIN.OBJECT, помимо поддержки S3-протокола, включает нативный SDK, который ускоряет миграцию минимум на 25%, а больший прирост производительности зависит от особенности реализации системы. Кроме того, SDK предоставляет низкоуровневый доступ к записи в хранилище из пользовательского кода.