Мультитиринг
Мультитиринг — поддержка в VK Object Storage нескольких классов хранения (Storage Class, тиров). Каждый тир сопоставлен физическому хранилищу (Storage) с собственными характеристиками скорости доступа и надежности.
В разделе:
- Класс хранения (Storage Class).
- Примеры тиров и различия между ними.
- Атрибуты класса хранения.
- Ручной перевод объекта на другой тир.
- Тачинг и удаление объектов между тирами.
- Фоновая миграция объектов между тирами.
- Логический и физический класс: биллинг и фактическое размещение.
- Администрирование мультитиринга.
Класс хранения описывается двумя сущностями:
- Логический класс — виртуальное расположение объекта, которое видит пользователь.
- Физический тир — фактическое расположение объекта, используется только внутри системы для направления в нужное хранилище.
В идеальных условиях логический и физический класс объекта совпадают. При смене класса физический класс должен стать идентичным логическому.
Атрибут | Описание |
|---|---|
| Идентификатор класса хранения (например, |
| Имя класса хранения (например, |
| Ссылка на физический тир, на котором фактически расположены данные класса |
| GB-сервис для биллинга (например, |
| Список разрешенных переходов на другие классы (whitelist) — явный разрешенный граф переходов между тирами |
| Feature-атрибуты класса хранения, см. Атрибуты класса хранения |
Атрибут | Описание |
|---|---|
| Идентификатор физического тира (например, |
| Имя физического тира |
| Список эндпоинтов для доступа к API хранилища тира |
| Префикс в Etcd для доступа к Nylon тира (для поддержки тачинга, touching) |
| Тип авторизации при обращении к API хранилища тира и учетные данные (credentials) для нее |
Единая конфигурация логических классов и физических тиров — 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.
Логический класс | Физический тир | Нештрафуемый порог хранения, дней | Особенности |
|---|---|---|---|
|
| 0 | Класс без ограничений, доступен всем по умолчанию |
|
| 30 | Нештрафуемый порог хранения — 30 дней |
|
| 90 |
|
|
| 0 |
|
Один и тот же физический тир может обслуживать несколько логических классов одновременно — как в примере с ST, GL и BK, для которых physical_id = HOT.
Логика сервисов не привязывается к конкретным именам классов хранения (например, сервис не проверяет, является ли класс GLACIER), а опирается на атрибуты класса. Это позволяет добавлять новые классы хранения без изменения кода сервисов — достаточно выставить существующие атрибуты в конфигурации.
Атрибут | По умолчанию | Описание |
|---|---|---|
| — | Имя алгоритма компрессии. Атрибут логического класса. Несколько логических классов на одном физическом тире могут использовать разную компрессию |
|
| Класс недоступен для использования на проектах по умолчанию. Клиент не может указать приватный класс в |
| 0 | Минимальный срок хранения для биллинга — нештрафуемый порог |
|
| Если |
|
| Класс доступен только для запросов с заголовком |
Перевод объекта на другой класс хранения вручную выполняется операцией 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 для таких объектов возвращает ошибку. Перенос состоит из трех шагов:
CreateMultipartUpload— резервирование сессии с новым классом хранения и выдачаUploadId.UploadPartCopy(повторяется для каждой части) — чтение диапазона байт исходного объекта и запись временного фрагмента.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.
|
|
|
|---|---|---|
|
|
|
|
|
|
Объекты с class = STANDARD_IA и pclass = HOT — кандидаты на физическую миграцию.
Процесс миграции последовательно перебирает объекты (full scan) и для каждого батча выполняет:
- Фильтрацию по условию
pclass = HOT and class = STANDARD_IA. - Копирование данных отфильтрованных объектов на целевой тир через API хранилища и обновление их
pclass. - Сохранение курсора (последнего обработанного первичного ключа) для продолжения обработки после рестарта без повторного прохода с начала.
Миграция выполняется сервисом, запускаемым администратором по требованию (on demand), а не разовым скриптом, так как операция может длиться недели на больших инсталляциях и должна поддерживать:
- управление —
Start,Stop,Pause/Resume; - наблюдаемость — прогресс (количество обработанных и оставшихся объектов), логирование, метрики скорости миграции и объема перенесенных данных;
- ограничение нагрузки на хранилище и Matter: раздельные RPS-лимитеры для
SELECT(чтение с реплики) иUPDATE(запись на мастер-ноду) в Matter, а также лимит пропускной способности прокачки данных через хранилище.
Логический и физический класс хранения решают разные задачи:
class— то, что видит пользователь и биллинг. Именно логический класс определяетgb_service, по которому считается стоимость хранения.pclass— то, где данные фактически лежат. Используется только для направления запросов к нужному хранилищу черезapi_urlsфизического тира и не влияет на биллинг.
В штатном режиме оба поля объекта совпадают. Расхождение возникает временно — например, в процессе миграции схемы (Миграция схемы метаданных) или во время фоновой физической миграции (Физическая миграция) — и в конечном итоге устраняется: физический класс должен стать идентичным логическому.