Перейти к содержанию

Диски

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

Коротко

  • Диск S3R — директория, а не устройство. Кластер узнаёт диск по суперблоку в ней и без суперблока этого диска ничего не форматирует.
  • Ёмкость и размер экстента фиксируются при форматировании. Всё место диска занимается в файловой системе сразу, поэтому df не показывает объём данных.
  • Накопители подключают без RAID, а кэш записи без защиты от потери питания отключают: иначе подтверждённые записи теряются при отключении питания.

Идентификация диска

Диском S3R служит директория локальной файловой системы. При регистрации в ней создаётся суперблок — служебная запись с постоянным идентификатором диска, идентификатором кластера и номером форматирования. Записи о размещении ссылаются на идентификатор диска, а не на путь.

Каждый диск записан строкой таблицы s3r_disk: инстанс (имя и UUID), путь, ярус, поддомен, геометрия, номер форматирования и состояние. После первого запуска инстанс монтирует диски по своим строкам этой таблицы, а не по списку из конфигурации. За изменениями строк он следует без перезапуска: монтирует добавленный диск, форматирует переформатированный и отключает удалённый.

Состояния диска

Состояние Значение
new диск зарегистрирован и ещё не работает; его шаг показан в разделе Шаги нового диска
active диск работает
draining диск переводится в обслуживание; его участники переносятся на другие диски
failed диск признан вышедшим из строя; его участники заменяются другими дисками
blank, foreign, corrupt по пути диска нет его собственного накопителя; участники удерживаются: диск остаётся в группах, кластер ждёт его возвращения (см. Неисправность суперблока)

Замена и удержание участников

Участник группы — это диск в её составе. Когда диск перестаёт работать, кластер поступает с его участниками одним из двух способов.

Что происходит с участником Что это значит Когда применяется
Заменяется место диска в группе занимает другой диск, и фрагменты заново вычисляются на нём по остальным участникам. Прежний диск в группу не возвращается диск признан вышедшим из строя (failed). При выводе диска (draining) участники тоже переходят на другие диски, но данные переносятся с самого диска
Удерживается диск остаётся в составе группы, кластер ждёт его возвращения и ничего не перестраивает. Пока диска нет, группа работает без одного участника диск или его узел недоступен, но вышедшим из строя не признан

Удержание рассчитано на временные отказы: после возвращения диска достаточно дописать то, что он пропустил. Диск, который перестал отвечать, кластер сам вышедшим из строя не признаёт: это решение принимает администратор (см. Действия с дисками).

Неисправность суперблока

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

Состояние Что найдено по пути
blank (пустой) суперблока нет. Так выглядит и пустой накопитель, и файловая система, которая ещё не смонтирована
foreign (чужой) суперблок проверен, но принадлежит другому диску или другому кластеру, например накопитель другого инстанса
corrupt (повреждённый) любой другой суперблок: слишком короткий, не прошедший проверку контрольной суммы или с более старым номером форматирования этого диска

Участники групп на таком диске не заменяются, а удерживаются, как у недоступного узла. В журнал выводится ошибка:

disk <id> is <состояние>: <причина>. It is not formatted; its members are held. Mount its own drive at <путь>, reformat it to put a new drive there, or declare it failed

Состояние снимается одним из двух способов:

  • само, когда монтирование находит по пути суперблок этого диска с номером форматирования из его строки;
  • действием «Переформатировать» (см. Действия с дисками).

Шаги нового диска

Диск в состоянии new проходит шаги. В таблице они не хранятся, а выводятся из строки диска и записи яруса. Ответ GET /v2/disks показывает шаг в поле step:

Шаг Значение
formatting диск ожидает форматирования или форматируется
waiting for the tier's shape у яруса диска ещё нет записанной схемы избыточности, и данные на нём не размещаются
mounting диск монтируется; если монтирование не удалось, диск остаётся на этом шаге

Если шаг не удался, поле step_error содержит последнюю ошибку. Её знает только инстанс диска, поэтому ответ другого инстанса содержит в этом поле null. Причина всегда записана и в журнале инстанса диска.

Размер экстента

Место на диске разделено на экстенты — файлы одинакового размера, в которые записываются фрагменты.

Размер экстента выбирается один раз

Размер экстента одинаков для всех дисков кластера и задаётся при установке плагина параметром контекста миграции extent_size. После форматирования первого диска команда ALTER PLUGIN, изменяющая этот параметр, отклоняется.

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

  • конфигурация диска с параметром extent_bytes отклоняется;
  • диск, отформатированный с другим размером экстента, не монтируется, и плагин выводит оба размера.

Как выбрать размер, описано в разделе Выбор ёмкости и размера экстента.

Ёмкость диска

Как задаётся ёмкость

Ёмкость диска задаётся параметром capacity в YAML либо числовым полем S3R_DISKS. Значение — число байтов либо число с двоичной единицей KiB, MiB, GiB или TiB, например 4TiB. Диск с ёмкостью, записанной иначе, не монтируется.

Число экстентов вычисляется из ёмкости при форматировании:

extent_count = floor((capacity − 131072) / extent_size)

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

Ёмкость диска с данными не меняется

Для диска с данными число экстентов не меняется. Чтобы задать другую ёмкость, нужна новая пустая директория. Ёмкость отформатированного диска берётся из его суперблока, и значение в конфигурации на неё не влияет.

Ёмкость нового накопителя

Диск форматируется на новом накопителе в трёх случаях: он добавлен действием «Добавить диск», переформатирован действием «Переформатировать» или принят инстансом на месте исключённого. Ёмкость прежнего накопителя ему не передаётся. Она определяется при форматировании в таком порядке:

  1. значение capacity записи с тем же путём в локальном списке дисков инстанса;
  2. значение capacity_bytes из запроса действия;
  3. место файловой системы, измеренное при форматировании, по правилам следующего раздела.

Когда ёмкость можно не задавать

Ёмкость можно не задавать, только если в директорию диска смонтирована отдельная файловая система. Тогда диск занимает всё место файловой системы, доступное непривилегированным процессам (f_bavail). Метаданные файловой системы и резерв суперпользователя в ёмкость не входят.

В остальных случаях плагин не определяет размер диска. Диск не форматируется и в журнал выводится ошибка с указанием задать capacity, если:

  • директория не является точкой монтирования отдельной файловой системы;
  • на одной файловой системе находятся несколько дисков инстанса без заданной ёмкости.

Отдельной файловой системой не считаются:

  • корневая директория /;
  • подтом btrfs, смонтированный параметром subvol;
  • поддиректория, смонтированная командой mount --bind.

К уже отформатированному диску эта проверка не применяется: его ёмкость берётся из суперблока.

Выделение места при монтировании

При первом монтировании плагин заранее выделяет в файловой системе место под все экстенты диска, поэтому вся ёмкость занимается сразу.

Файловая система диска должна поддерживать заблаговременное выделение места вызовом posix_fallocate, как ext4 и XFS. Если она его не поддерживает, диск не монтируется и в журнал выводится ошибка.

Места может не хватить, например, когда заданная ёмкость превышает свободное место. В этом случае:

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

Столбец capacity_bytes таблицы s3r_disk показывает суммарный размер всех экстентов и области суперблока, включая экстенты, под которые место не выделено.

Заполнение экстентов нулями

Заранее выделенное место файловая система помечает как незаписанное. Запись фрагмента в незаписанную область заставляет файловую систему преобразовать её в записанную. На XFS запись, которая заканчивается внутри блока, дробит карту блоков файла. Запись идёт в несколько раз медленнее, а примерно на 15 млн мелких объектов рост карты завершается ошибкой нехватки места, хотя место на диске есть.

Поэтому участник, выделяя экстент группе, сначала заполняет экстент нулями и только затем записывает его заголовок:

  • если ядро (Linux 6.17 или новее) и файловая система поддерживают вызов fallocate с флагом FALLOC_FL_WRITE_ZEROES, нули записывает файловая система, а устройство может выполнить эту запись само;
  • иначе плагин записывает нули блоками по 4 МиБ.

Экстент в 1 ГиБ заполняется примерно за 0,2 с на NVMe и примерно за 1 с на диске со скоростью записи 1 ГБ/с.

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

Записи в группу не ждут заполнения её экстентов:

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

Исключение — начальное формирование. Экстенты начальных групп, первые и запасные, заполняются при формировании, и кластер начинает принимать записи только после этого. На каждом диске при этом заполняется 2 × (1 + spare_extents) экстентов на каждую начальную группу с участником на этом диске. Начальное формирование длится дольше на время этих записей: например, около 20 с для пяти групп с экстентами по 1 ГиБ на диске со скоростью записи 1 ГБ/с.

Выбор ёмкости и размера экстента

Команда df показывает диск заполненным

Место под экстенты выделяется при первом монтировании, поэтому df сразу показывает ёмкость диска как занятую, даже пока объектов нет. Это ожидаемое поведение, и объём данных по df не определяется.

Чем измерять занятое место:

Наименьший диск. Диск принимается при форматировании, если вмещает область суперблока и хотя бы один экстент. Диск меньшего размера не форматируется, и в журнал выводится ошибка not enough for even one ... extent plus the superblock. Для работы диску нужно не меньше двух экстентов: группа размещения по мере записи выделяет на каждом своём диске по экстенту для крупных и для малых блоков.

Размер экстента. Параметр migration_context.extent_size принимает кратное 4 КиБ значение от 16 МиБ до 2 ГиБ; рекомендуемое значение — 1 ГиБ. От размера зависит следующее:

  • Диск выделяет место группе, резервируя один или несколько экстентов. Когда все блоки экстента освобождаются, место снова становится доступным. Меньший экстент освобождается раньше.
  • При меньшем экстенте экстентов на диске больше, а при монтировании плагин читает заголовок каждого из них.
  • Остаток ёмкости меньше одного экстента не используется.

Предел одной группы на диске. Экстент состоит из блоков двух классов:

  • крупный блок содержит фрагмент полосы размером stripe_size / k и заголовок 4 КиБ;
  • малый блок равен 2 × inline_max.

Группа вмещает на каждом своём диске не более 65 536 крупных и 8 388 608 малых блоков. Поэтому одна группа использует на одном диске:

  • под фрагменты крупных объектов — не больше 65 536 × (stripe_size / k + 4 КиБ);
  • под малые блоки — не больше 64 ГиБ при inline_max, равном 4 КиБ.

Остальную ёмкость диска занимают другие группы, в которые он входит. При stripe_size, равном 2 МиБ:

Схема Крупный блок Предел одной группы под крупные объекты на диске
репликация, фрагмент равен полосе 2 МиБ + 4 КиБ 128,25 ГиБ
k = 2 1 МиБ + 4 КиБ 64,25 ГиБ
k = 4 512 КиБ + 4 КиБ 32,25 ГиБ
k = 8 256 КиБ + 4 КиБ 16,25 ГиБ

Предел растёт вместе с stripe_size: например, stripe_size, равный 8 МиБ, при k = 2 даёт фрагмент 4 МиБ и около 256 ГиБ на диск. Ограничения на размер полосы перечислены в разделе Выбор схемы избыточности яруса.

Домен отказа диска

Домен отказа диска состоит из домена отказа его инстанса без компонента dc и поддомена диска:

инстанс dc=msk,rack=msk-r3   диск (не задан)  ->  rack=r3
инстанс dc=msk,rack=msk-r3   диск hba=a       ->  rack=r3,hba=a
инстанс host=node1           диск hba=a       ->  host=node1,hba=a

Участники одной группы находятся в разных доменах отказа дисков. Как домены объявляются, почему из значений убирается префикс площадки <dc>- и как домены сравниваются, объяснено в разделе Домен отказа. Значение без такого префикса сравнивается как есть.

Ниже — то, что относится к самим дискам.

Единицу отказа выбирает администратор. Домен сравнивается целиком, поэтому набор компонентов определяет, что считается отказывающим вместе. Компонент rack распределяет группу по стойкам. Компонент host внутри одной стойки распределяет её по узлам этой стойки; это нужно стойке с собственной внутренней сетью (InfiniBand, RDMA).

Домен объявляется. Сам инстанс компонентом домена не считается. Диск не может быть участником группы, если у его инстанса нет компонентов, кроме dc, и сам диск поддомена не объявил: такая группа отклоняется с причиной no_failure_domain.

Поддомен не содержит dc и компонентов домена инстанса. Площадку задаёт только инстанс, а поддомен различает лишь то, что находится внутри инстанса. Поддомен, который содержит dc или компонент, объявленный в failure_domain самого инстанса (например, rack), отклоняется:

  • список дисков с таким поддоменом — при первом запуске;
  • действие «Добавить диск» с таким поддоменом — с ответом 400.

Повторяющихся доменов в группе не бывает. Отсюда два следствия:

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

Нехватка доменов останавливает замену участников

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

Дисковая подсистема

Кэш записи без защиты от потери питания

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

Диски рекомендуется подключать без RAID: как JBOD или через HBA в режиме прямого доступа (passthrough), по одной записи S3R_DISKS на физический диск. Причины:

  • Избыточность обеспечивает сам S3R. RAID с контролем чётности под ним добавляет вторую избыточность, которая защищает от тех же отказов, но накладные расходы при этом перемножаются.
  • Надёжность групп размещения рассчитывается по поддоменам дисков, которые задаёт администратор. Плагин не проверяет, соответствуют ли они оборудованию.

Если без RAID обойтись нельзя

Домены отказа размечаются по оборудованию. Логические тома одного массива при отказе контроллера выходят из строя одновременно, поэтому они образуют один диск хранилища, а не несколько дисков в одном поддомене: два диска яруса с одинаковым поддоменом на одном инстансе отклоняются. То же относится и к нескольким директориям на одном устройстве. Ёмкость такого диска задаётся явно (см. Ёмкость диска).

Проверка разметки

Разметку проверяют после развёртывания:

  • GET /-/debug/topology показывает, какие первые группы были бы созданы из текущих дисков, их раскладку и поле survives_instance_loss, а также причины, по которым группы не создаются;
  • GET /s3gateway/api/v2/placement-groups API управления показывает для каждой существующей группы поля failure_domains, distinct_domains, survives_instance_loss, layout и intended.

Поле survives_instance_loss показывает, переживает ли группа потерю любого одного домена отказа инстанса. Группа в раскладке instance его потерю не переживает.

Поля вычисляются по объявленным доменам

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

См. также