Перейти к основному содержанию Перейти к навигации Перейти к нижнему колонтитулу
Ограниченное время: Программа Design Partner — тариф BUSINESS навсегда

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

Наш отчёт о состоянии хранилища помечает репозитории с почти 20 000 экстентов на гигабайт. Цифра звучит тревожно. Я провёл последовательные и случайные тесты чтения на самых проблемных репозиториях: штраф оказался нулевым. Вот данные и объяснение, почему Rediacc не поставляет команду дефрагментации.

Кратко. rdc machine query --storage-health в Rediacc выводит показатель фрагментации для каждого репозитория. На одной рабочей машине GitLab помечается примерно 19 650 экстентами на гигабайт. Инстинкт подсказывает дефрагментировать. Я решил измерить.

  • Репозиторий, фрагментированный в 16 раз сильнее соседнего, читался со скоростью 149 MB/s против 143 MB/s последовательно и был быстрее на случайных чтениях 4K (719 vs 957 микросекунд).
  • Устройство флеш-памяти. Фрагментация бьёт по вращающимся дискам через время позиционирования головки. На SSD почти не остаётся механизма, через который она могла бы навредить.
  • Запуск btrfs filesystem defragment здесь разорвёт совместное использование примерно 250 ГБ reflink-форков и снапшотов в пул с 4,4 ГБ свободного места. Это реальный риск, а бенчмарк говорит, что взвешивать его не с чем.

Отчёт о состоянии хранилища существует, чтобы ответить на один вопрос: куда уходит мой диск. Он показывает размер каждого репозитория, сколько данных он разделяет со своими форками и показатель фрагментации. Последняя цифра может выглядеть пугающе. На моей машине образ репозитория GitLab сообщает 268 771 экстент при 14,6 ГБ. Это около 19 650 экстентов на гигабайт, и инструмент помечает его как “высокий”.

Рефлекс, который следует за этим, автоматический. Высокая фрагментация, значит нужно дефрагментировать. Я прописывал этот рефлекс в shell-скрипты для вращающихся дисков пятнадцать лет. Прежде чем добавить кнопку дефрагментации в Rediacc, я хотел узнать, чего эта цифра реально стоит на том железе, которое мы используем. Поэтому я провёл бенчмарк на живой машине.

Что цифра на самом деле считает

Репозиторий Rediacc это единственный файл образа LUKS, живущий в пуле btrfs. Показатель фрагментации получается запуском filefrag на этом файле образа. Он считает экстенты зашифрованного контейнера, а не файлы, которые читает ваше приложение внутри него.

Это важно из-за того, как уложены данные. Снизу вверх: физический SSD, затем корневая файловая система ext4 хоста, затем файл пула на loop-устройстве, затем loop0, затем пул btrfs, затем образ LUKS, затем устройство device-mapper crypt, затем внутренняя ext4, которую видят контейнеры. btrfs работает по принципу copy-on-write. Каждая случайная запись внутри репозитория создаёт новый экстент в образе. Базы данных и overlay-слои контейнеров пишут случайно весь день, поэтому образ накапливает экстенты по своей природе.

Файлы внутри тома это другая история. Я проверил репозиторий GitLab: его бинарный файл gitaly находится в 10 экстентах, git pack-файл в 17. Внутренняя файловая система не фрагментирована. Цифра 19 650 на гигабайт описывает copy-on-write контейнер, что именно и следует ожидать от него, и не говорит ничего о том, медленные ли операции чтения.

Бенчмарк

Я взял два репозитория с противоположных концов шкалы фрагментации и читал с них через direct IO, который обходит кеш страниц и вынуждает к физическому чтению.

РепозиторийСредний экстентЭкстентов на GBПоследовательное чтение
GitLab54 KB~19 650149 MB/s
Демо Stack Overflow880 KB~1 190143 MB/s

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

РепозиторийЗадержка случайного чтения 4KIOPS
GitLab (фрагментированный)719 us1 390
Демо Stack Overflow (менее фрагментированный)957 us1 045

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

Пропускная способность скромная в абсолютных числах: около 145 MB/s и 1 000 IOPS, потому что устройство это виртуализированный диск на общем хосте, а путь данных глубокий. Этот потолок задаётся уровнями виртуализации и шифрования, выше и ниже btrfs. Дефрагментация образа не способна его поднять.

Единственное, чего стоит фрагментация

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

  • filefrag на GitLab (268 771 экстент): 3,19 с
  • filefrag на демо Stack Overflow (152 364 экстента): 0,74 с

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

Почему Rediacc не поставляет команду дефрагментации

btrfs filesystem defragment не сохраняет reflinks примерно с ядра 3.9. Страница руководства говорит об этом прямо: дефрагментация разрывает reflinks copy-on-write данных и может вызвать значительное увеличение использования пространства. Перезапись файла последовательно копирует каждый общий экстент в приватный.

На этой машине почти всё является общим. Форки разделяют данные родителя через reflinks, а таймер резервных копий добавляет снапшоты только для чтения, которые тоже делятся. Пул заполнен на 99% при 4,4 ГБ свободного места. GitLab общий на 97%, поэтому его дефрагментация попыталась бы скопировать примерно 14 ГБ в 4,4 ГБ и прервалась на полпути. Демо Stack Overflow занимает 137 ГБ при 26 МБ уникальных данных, поэтому его дефрагментация попыталась бы материализовать 137 ГБ, которых физически не существует. Во всех репозиториях reflink-общими являются около 250 ГБ. Проход дефрагментации это бомба для дискового пространства, а не тюнинг.

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

Что читать вместо фрагментации

Столбец, заслуживающий вашего внимания в том же отчёте, это расхождение (divergence). Это процент образа репозитория, уникального для него, а не разделяемого с форками и снапшотами. Свежий форк находится около 0%, потому что он разделяет почти всё. Репозиторий, в который активно писали с момента форка, движется к 100%.

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

Вывод

Показатель фрагментации реален, и на copy-on-write образе под случайными записями он всегда будет выглядеть высоким. На флеш-памяти он информационный. Я измерил 16-кратный разброс и не обнаружил штрафа за чтение, более быстрый профиль случайных операций на более фрагментированном файле и единственную небольшую стоимость в виде времени фонового сканирования. Инструмент, который бы “исправил” число, вместо этого разорвал бы четверть терабайта reflinks форков в пул, которому для них нет места.

Поэтому Rediacc сообщает о фрагментации и объясняет её, но не предлагает кнопку для действия. Честный инженерный ответ был в том, чтобы измерить предположение, а не автоматизировать рефлекс.