VK Object Storage logo
Помощь

Мультитиринг

Мультитиринг — поддержка в VK Object Storage нескольких классов хранения (Storage Class, тиров). Каждый тир сопоставлен физическому хранилищу (Storage) с собственными характеристиками скорости доступа и надежности.

В разделе:

Класс хранения (Storage Class)

Класс хранения описывается двумя сущностями:

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

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

Таблица 1 — Атрибуты логического класса хранения

Атрибут

Описание

id

Идентификатор класса хранения (например, ST)

name

Имя класса хранения (например, STANDARD)

physical_id

Ссылка на физический тир, на котором фактически расположены данные класса

gb_service

GB-сервис для биллинга (например, s3h, s3i, s3b, s3g)

allowed_transitions

Список разрешенных переходов на другие классы (whitelist) — явный разрешенный граф переходов между тирами

feature.*

Feature-атрибуты класса хранения, см. Атрибуты класса хранения

Таблица 2 — Атрибуты физического тира

Атрибут

Описание

id

Идентификатор физического тира (например, HOT)

name

Имя физического тира

api_urls

Список эндпоинтов для доступа к API хранилища тира

nylon_etcd_prefix

Префикс в Etcd для доступа к Nylon тира (для поддержки тачинга, touching)

auth.type, auth.credentials

Тип авторизации при обращении к API хранилища тира и учетные данные (credentials) для нее

Хранение конфигурации в Etcd

Единая конфигурация логических классов и физических тиров — Etcd. Каждый сервис читает конфигурацию из Etcd один раз при старте и кэширует ее локально, а при изменении конфигурации получает обновление через Watch без дополнительных запросов к Etcd. Запись в Etcd происходит только при ручном изменении конфигурации администратором.

Так как каждый сервис самостоятельно определяет нужный физический тир по классу объекта на основе локального кэша, маршрутизация распределена между сервисами — отдельного сервиса-маршрутизатора нет. Использование Etcd различается в зависимости от роли сервиса:

  • сервисы, которые напрямую обращаются к данным через Storage API (Hitrod, Hint, Xerox, сервис фоновой миграции, Hilt), определяют нужный эндпоинт через атрибут api_urls физического тира;
  • сервисы, участвующие в тачинге (Hitbox, Go-toucher), используют атрибут nylon_etcd_prefix физического тира — префикс в Etcd для доступа к Nylon соответствующего тира.

Имена логического и физического класса, которые указываются при запуске сервиса фоновой миграции в качестве src/dst (см. Фоновая миграция объектов между тирами), должны совпадать с классами, заведенными в Etcd при первичной настройке.

На каждом объекте фактически хранятся два поля класса:

  • class — виртуальное расположение, видно пользователю;
  • pclass — фактическое расположение, используется для направления запроса в соответствующее физическое хранилище.

Примеры тиров и различия между ними

Ниже приведен пример конфигурации логических классов и их сопоставления с физическими тирами HOT и COLD.

Таблица 3 — Пример логических классов и их отличий

Логический класс

Физический тир

Нештрафуемый порог хранения, дней

Особенности

ST (STANDARD)

HOT

0

Класс без ограничений, доступен всем по умолчанию

IA (STANDARD_IA)

COLD

30

Нештрафуемый порог хранения — 30 дней

GL (GLACIER)

HOT

90

feature.private = true (доступен только после активации администратором для проекта); feature.restored = true — GET без предварительного восстановления возвращает 403

BK (BACKUP)

HOT

0

feature.s2s = true — доступен на запись только для внутренних сервисов (запрос с заголовком X-Mcs-S2s), для внешних клиентов класс доступен только на чтение

Один и тот же физический тир может обслуживать несколько логических классов одновременно — как в примере с ST, GL и BK, для которых physical_id = HOT.

Атрибуты класса хранения

Логика сервисов не привязывается к конкретным именам классов хранения (например, сервис не проверяет, является ли класс GLACIER), а опирается на атрибуты класса. Это позволяет добавлять новые классы хранения без изменения кода сервисов — достаточно выставить существующие атрибуты в конфигурации.

Таблица 4 — Атрибуты класса хранения

Атрибут

По умолчанию

Описание

feature.compression

—

Имя алгоритма компрессии. Атрибут логического класса. Несколько логических классов на одном физическом тире могут использовать разную компрессию

feature.private

false

Класс недоступен для использования на проектах по умолчанию. Клиент не может указать приватный класс в PUT/CopyObject, пока администратор не активирует его для конкретного проекта через API Hilt (POST /v2/projects/storage_class/activate / .../deactivate)

feature.min_storage_days

0

Минимальный срок хранения для биллинга — нештрафуемый порог

feature.restored

false

Если true, GET без предварительного восстановления возвращает 403

feature.s2s

false

Класс доступен только для запросов с заголовком X-Mcs-S2s. Внешние клиенты могут только читать объекты такого класса, запись доступна только через s2s

Ручной перевод объекта на другой тир

Перевод объекта на другой класс хранения вручную выполняется операцией CopyObject, где источник и назначение — один и тот же объект, но с другим значением x-amz-storage-class (self-copy). Поведение аналогично AWS S3.

$ aws s3 cp \  s3://my-bucket/my-object \  s3://my-bucket/my-object \  --storage-class STANDARD_IA

Если заголовок x-amz-storage-class не указан, объект загружается в класс хранения по умолчанию, заданным для бакета.

При получении запроса CopyObject целевое хранилище определяется через Etcd, после чего сравнивается с pclass исходного объекта:

  • если целевое хранилище совпадает с pclass и не сработал ни один из триггеров физического копирования (multipart-объект, запрошен x-amz-copy-source-range, применяется шифрование) — копируются только метаданные, байты не переносятся;
  • если целевое хранилище отличается — выполняется физическое копирование данных между тирами.

Метаданные объекта обновляются атомарно: метаданные объекта назначения записываются только после успешного завершения копирования данных, до этого момента объект назначения недоступен для чтения. После копирования данные исходного объекта не удаляются немедленно — они помечаются на удаление тачингом и физически удаляются в рамках отдельного процесса Touch → Mark → Sweep, см. Тачинг и удаление объектов между тирами.

Объекты размером более 5 ГБ переносятся через UploadPartCopy, так как CopyObject для таких объектов возвращает ошибку. Перенос состоит из трех шагов:

  1. CreateMultipartUpload — резервирование сессии с новым классом хранения и выдача UploadId.
  2. UploadPartCopy (повторяется для каждой части) — чтение диапазона байт исходного объекта и запись временного фрагмента.
  3. CompleteMultipartUpload — склейка фрагментов в финальный объект с новым классом хранения, удаление временных фрагментов и исходного объекта (если ключ совпадает).

Тачинг и удаление объектов между тирами

Удаление объектов в VK Object Storage выполняется асинхронно в три фазы: Touch, Mark и Sweep.

  • Touch — сервис Go-toucher обходит метаданные и для каждого найденного объекта отправляет батчи хешей через nylon.api.storage.multi_touch, обновляя отметку touch = now.
  • Mark — периодическая задача в FileDB помечает объект как DELETED, если его touch не обновлялся заданное число раз подряд.
  • Sweep — сервис Haron сверяет физическое хранилище с FileDB через nylon.api.storage.sync_hashes. Если объект помечен DELETED, Haron получает резолюцию remove_old и физически удаляет файл.

Таким образом, тачинг (фаза Touch) только поддерживает отметку «объект жив» для объектов, присутствующих в метаданных, а фактическое удаление выполняет Haron на фазе Sweep.

В условиях мультитиринга у каждого физического тира — собственный FileDB и Nylon, поэтому тачинг должен учитывать pclass объекта:

  • Go-toucher при парсинге метаданных определяет pclass объекта и маршрутизирует multi_touch на Nylon соответствующего тира;
  • Hitbox поднимает отдельный Nylon-клиент на каждый тир (путь до Nylon берется из атрибута nylon_etcd_prefix физического тира, см. Класс хранения (Storage Class)) и при переходе между стадиями тачинга вызывает соответствующий метод (nylon.api.touching.start/.complete/.cancel) на всех тирах — переход к следующей стадии происходит только если вызов был успешным на каждом тире.

Фоновая миграция объектов между тирами

До разделения класса объекта на логический и физический два класса хранения — STANDARD и STANDARD_IA — определяются на одно физическое хранилище. Объекты логически определяющиеся классом STANDARD_IA, физически лежат там же, где STANDARD.

Миграция в COLD выполняется в два этапа.

Миграция схемы метаданных

Единоразовая процедура разделения поля class объекта на class и pclass.

Таблица 5 — Заполнение полей при миграции схемы

class

class

pclass

STANDARD

STANDARD

HOT

STANDARD_IA

STANDARD_IA

HOT

Объекты с class = STANDARD_IA и pclass = HOT — кандидаты на физическую миграцию.

Физическая миграция

Процесс миграции последовательно перебирает объекты (full scan) и для каждого батча выполняет:

  1. Фильтрацию по условию pclass = HOT and class = STANDARD_IA.
  2. Копирование данных отфильтрованных объектов на целевой тир через API хранилища и обновление их pclass.
  3. Сохранение курсора (последнего обработанного первичного ключа) для продолжения обработки после рестарта без повторного прохода с начала.

Миграция выполняется сервисом, запускаемым администратором по требованию (on demand), а не разовым скриптом, так как операция может длиться недели на больших инсталляциях и должна поддерживать:

  • управление — Start, Stop, Pause/Resume;
  • наблюдаемость — прогресс (количество обработанных и оставшихся объектов), логирование, метрики скорости миграции и объема перенесенных данных;
  • ограничение нагрузки на хранилище и Matter: раздельные RPS-лимитеры для SELECT (чтение с реплики) и UPDATE (запись на мастер-ноду) в Matter, а также лимит пропускной способности прокачки данных через хранилище.

Логический и физический класс: биллинг и фактическое размещение

Логический и физический класс хранения решают разные задачи:

  • class — то, что видит пользователь и биллинг. Именно логический класс определяет gb_service, по которому считается стоимость хранения.
  • pclass — то, где данные фактически лежат. Используется только для направления запросов к нужному хранилищу через api_urls физического тира и не влияет на биллинг.

В штатном режиме оба поля объекта совпадают. Расхождение возникает временно — например, в процессе миграции схемы (Миграция схемы метаданных) или во время фоновой физической миграции (Физическая миграция) — и в конечном итоге устраняется: физический класс должен стать идентичным логическому.