Кэш, нагрузка и ловушка средних значений: почему storage-бенчмарки вводят в заблуждение
Пример пирамиды хранения данных по версии Цадока
Представьте ситуацию: разработчики внедрили в файловую систему прозрачное шифрование, скомпилировали ядро и запустили утилиту Fio — пропускная способность осталась прежней. Однако после развертывания в production быстродействие резко снизилось. Проблема вовсе не в том, что бенчмарк солгал: он корректно зафиксировал пиковые возможности накопителя, тогда как издержки на шифрование попросту растворились за дисковыми задержками. Именно так рождается один из классических просчетов при тестировании СХД. Многие инженеры до сих пор склонны воспринимать хранение данных как примитивную подсистему: файловая система, блочный интерфейс и базовый показатель пропускной способности. На деле же это один из самых коварных элементов стека, где разница в скорости между предельно быстрыми и самыми медленными операциями составляет 4–8 порядков, а слои виртуализации (вроде LVM, программных RAID и NFS) соседствуют с постоянными переключениями контекста между ядром ОС и пользовательским пространством.
Чтобы детально разобраться, как безошибочно оценивать производительность систем хранения, обратимся к докладу Эреза Цадока, профессора Университета Стони-Брук и руководителя Лаборатории файловых систем и хранения данных.
Почему же оценка СХД представляет такую сложность? Современная инфраструктура хранения давно переросла концепцию простого диска с единственной файловой системой. Каждый запрос преодолевает целый каскад уровней, и прежде чем приступать к тестам, критически важно осознать этот сложный путь.
В первом приближении иерархию памяти можно визуализировать в виде пирамиды: ее фундамент образуют емкие, но неторопливые жесткие диски, а вершину венчают микроскопические высокоскоростные регистры процессора и L1-кэш. Разрыв в производительности между этими крайними точками составляет те самые 4–8 порядков, причем все уровни непрерывно обмениваются данными.
Более того, актуальный стек хранения давно утратил строгую иерархичность. Архитектуру дополняют многочисленные прослойки виртуализации: LVM, программные RAID-контроллеры, а в случае сетевых хранилищ — протокол NFS и сопутствующие сетевые задержки. Не стоит забывать и о переносе логики в user-space. Из-за этого приходится принимать в расчет не только аппаратные задержки, но и накладные расходы на смену контекста вместе с дублированием данных между пространством ядра и пользовательскими приложениями.

Подобная многоуровневость объясняет, почему примитивные тесты столь редко отражают реальное положение дел в критически важных узлах системы.
Почему ваши бенчмарки ничего не доказывают
Для наглядности вернемся к упомянутому примеру с внедрением прозрачного шифрования на уровне файловой системы.
Допустим, модифицированная файловая система демонстрирует пропускную способность (throughput) на уровне 150 МБ/с. Контрольный запуск на стандартной ФС без шифрования показывает абсолютно те же 150 МБ/с.
На первый взгляд все отлично, однако велик риск того, что вместо эффективности алгоритмов шифрования мы просто уперлись в аппаратный предел пропускной способности винчестера.
Как такое возможно?
Система функционировала в режиме I/O-bound: пока накопитель отрабатывал запрос, центральный процессор успевал не только шифровать данные, но и выполнять прочие задачи, а нагрузка от криптографических модулей маскировалась задержками диска. Стоит лишь перенести аналогичный софт на производительную NVMe-платформу, как ситуация кардинально изменится. В этом случае узким горлышком станет уже не накопитель, а вычислительная мощность CPU. И тогда тот же механизм шифрования, казавшийся на HDD «бесплатным», неожиданно обрушит общую производительность СХД. Именно поэтому неверно выстроенная методология тестирования часто оборачивается серьезными проблемами на стадии эксплуатации.
Подобный разрыв между показаниями утилиты и реальным поведением системы наблюдается не только в синтетике. Показательный пример — оценка скорости записи посредством утилиты dd на уровне блочного интерфейса. Утилита dd генерирует последовательный однопоточный поток крупных блоков и по умолчанию не инициирует команду fsync до окончания работы. Информация уходит в страничный кэш (page cache), после чего dd рапортует об успешном завершении, в то время как ядро ОС все еще фоново сбрасывает данные на носитель. Реляционная база данных поверх той же СХД ведет себя принципиально иначе: каждая транзакция порождает случайный ввод-вывод (random I/O) для поиска нужной страницы, ее чтения, модификации и перестройки индексов. В результате dd легко рисует 500 МБ/с последовательного потока на том же железе, где реальная СУБД захлебывается на скромных 100–200 IOPS.
Каждое диагностическое средство обладает своей спецификой, а выбор зависит от конкретных целей тестирования. Чтобы подходить к этому осознанно, целесообразно изучить классификацию существующих бенчмарков.
Ограничения бенчмарков
Классифицируя бенчмарки в своем выступлении, Цадок выделяет несколько ключевых групп. Микробенчмарки превосходно подходят для изоляции конкретной функции, однако они совершенно не отражают комплексное поведение системы под нагрузкой. Макробенчмарки ближе к реальным сценариям, но все равно остаются синтетикой. Воспроизведение реальных трейсов (Trace Replay) выглядит наиболее достоверно, однако такие наборы быстро устаревают и зачастую с трудом поддаются воспроизведению…
Ни один из этих типов не является универсальной панацеей, поэтому эксперт призывает рассматривать их как взаимодополняющие методики и комбинировать все три подхода.
Если взять параметры из матрицы Цадока (представлена ниже) и перемножить их комбинации, итоговое количество итераций превысит тысячу. Учитывая необходимость пятикратного повторения каждого теста для нивелирования случайных погрешностей и выведения среднего значения, общая длительность испытаний возрастет нелинейно.

Даже при условии, что единичный прогон занимает минуту-две, стенд проработает в непрерывном режиме не меньше нескольких дней. Если же для выхода на стабильный режим требуется 10–15 минут на тест, эксперимент растягивается на долгие недели.
Специфика глубокого бенчмаркинга заключается еще и в том, что он неизбежно обнажает скрытые дефекты. Если за пару тысяч итераций ваша система столкнется с критическим сбоем ядра (kernel panic), после наложения патча процедуру тестирования придется запускать с самого начала.
Следовательно, на этапе проектирования архитектуры или оптимизации подсистемы хранения профессор Цадок настоятельно советует закладывать на фазу тестов, отладки и устранения регрессий больше времени, чем на написание самого кода.
Темное искусство визуализации
Сбор метрик — лишь половина дела. Самое увлекательное начинается при попытке наглядно представить этот массив данных.
Обратите внимание на типичный «некачественный график» из числа тех, что профессор регулярно обнаруживает в рецензируемых статьях.

Что не так с диаграммой?
Первое, что бросается в глаза — усеченная шкала. Подобный тройной прием на столбчатых диаграммах искусственно драматизирует различия.
Золотое правило для гистограмм (bar chart) гласит: отсчет по оси ординат должен начинаться с нуля. Если ось намеренно обрезена ради демонстрации микроскопических флуктуаций, об этом необходимо делать четкую пометку.
Кроме того, создатели неудачных графиков грешат сложночитаемыми величинами. К примеру, значения вроде 10 000 000 байт/с воспринимаются с трудом. Шкалы целесообразно нормализовать, переведя в МБ/с, Гіб/с, микросекунды или миллисекунды. При колоссальном разбросе данных выручает логарифмический масштаб, хотя интерпретируется он иначе, чем линейный.

Наконец, неудачный график вынуждает аудиторию заниматься самостоятельными вычислениями. Когда над столбцами красуются цифры вроде 8 299.18 и 10 278.98, наблюдатель должен в уме сопоставлять их, вычисляя превосходство одного решения над другим. Гораздо грамотнее сохранить абсолютные показатели на осях, а в текстовом блоке над графиком привести готовую интерпретацию: «+24%» или «1.24×». В этом случае диаграмма начинает давать ответы, а не служить источником дополнительных ментальных усилий.

Цадок предлагает ряд простых приемов, минимизирующих когнитивную утомляемость. Во-первых, имеет смысл явно указывать вектор «лучшего» результата: для пропускной способности подъем вверх желателен, тогда как для задержек — наоборот. Это легко обозначить визуально на осях либо в условных обозначениях. Во-вторых, вместо классических гистограмм продуктивнее использовать диаграммы размаха (box plot), наглядно демонстрирующие не только среднее, но и дисперсию значений.

И наконец, цветовую гамму следует подбирать с учетом того, чтобы материалы оставались контрастными при печати в градациях серого и были доступны людям с особенностями цветовосприятия.
Но фундаментальный элемент здесь — отображение достоверности. Самая опасная ошибка — демонстрация усредненных показателей без указания планок погрешности.
Предположим, тест зафиксировал проседание производительности тестируемого решения на 19% относительно эталона, однако доверительные интервалы обеих систем имеют большую ширину и перекрывают друг друга. С точки зрения математической статистики это означает, что с заданной вероятностью (например, 50%) истинное среднее может находиться в любой точке данного диапазона. Иными словами, тестируемая система могла не проиграть 19%, а напротив, показать прирост в 5%.
Обнаружив гигантские планки погрешностей (error bars), первым делом хочется замазать их и сделать вид, что все в порядке. На деле же это важный триггер для поиска глубинных причин нестабильности. Возможно, стоит увеличить число итераций. Не исключено, что посреди эксперимента активизировалась фоновая служба вроде cron и запустила updatedb, нарушив чистоту операций ввода-вывода. Либо же мы нащупали фундаментальный архитектурный изъян, проявляющийся лишь при определенном профиле нагрузки.

Грамотная визуализация лишь подсвечивает наличие аномалии, но не раскрывает ее природу. Если графики демонстрируют скачки или неожиданные задержки, приходится спускаться на уровень ниже — к профилированию стека хранения.
Как профилировать hot path без искажения результатов
Когда бенчмарк выдает пересекающиеся доверительные интервалы наряду с широкой дисперсией, истинные причины, как правило, скрываются в ядре операционной системы. Для локализации проблемного участка требуется идентифицировать функцию-виновника задержек, что влечет за собой ряд инструментальных сложностей.
По мнению профессора Цадока, стандартный инструментарий для подобных изысканий включает eBPF, tracepoints, blktrace и tcpdump. Они дают возможность отслеживать движение запроса сквозь весь стек СХД, генерировать гистограммы задержек на блочном уровне и изолировать отдельные фазы I/O.
Тем не менее, профилирование горячего пути (hot path) внутри ядра сопряжено с принципиальным нюансом: сама система мониторинга оказывает возмущающее воздействие на объект исследования.
Почему так происходит?
Цена работы самого измерительного инструмента интегрируется в результирующую метрику, из-за чего накладные расходы на профайлинг и длительность целевой операции могут оказаться соизмеримы. Чем короче исследуемый процесс и чем выше частота срабатывания событий, тем сильнее проявляется этот искажающий фактор.
В условиях умеренных нагрузок этим эффектом допустимо пренебречь. Например, запуская blktrace на накопителе, который по паспорту выдает 120 IOPS на случайных операциях размером 16 КБ, без инструмента мы видели бы лишь общую картину «диск тормозит», тогда как трассировка указывает на конкретную фазу возникновения задержки (детальный разбор доступен здесь).
Однако высокочастотные сценарии многократно усложняют задачу. Внутри базовых функций ядра, исполняющихся за микросекунды и вызываемых миллионы раз, издержки на мониторинг катастрофически искажают реальность. Так, при генерации 20 миллионов событий ввода-вывода в секунду стандартная утилита biolatency (на базе eBPF) утилизировала более половины процессорных ядер исключительно на обслуживание точек трассировки. При этом аппаратная латентность каждого запроса к NVMe исчислялась десятками микросекунд, а зонды добавляли к ним еще 16 мкс (подробности описаны в этой статье).
Откуда берется подобное влияние?
Механика этого искажения наглядно проявляется при работе с точками трассировки (tracepoints). Они аккумулируют события и сбрасывают их в неблокирующие кольцевые буферы (lock-free ring buffers) памяти ядра, откуда их асинхронно забирает демон в пользовательском пространстве. В условиях высокой интенсивности запросов это приводит к потере данных. Процесс не успевает вычитывать поток, буфер переполняется, и ядро отбрасывает новые события, делая собранную статистику нерелевантной.
Дополнительно генерация, сериализация и запись тысяч записей в буфер пожирают процессорные ресурсы, вымывают полезные данные из кэшей процессора (L1/L2) и модифицируют паттерны обращения к памяти. В результате исследуемая среда начинает функционировать иначе, нежели в штатном режиме без профайлера.
При этом детальный лог каждого события зачастую избыточен. Для выявления задержек важны не средние показатели, а полноценное распределение — гистограмма. Возникает вопрос: как сформировать гистограмму внутри горячего пути ядра с минимальными накладными расходами, избегая динамического выделения памяти и потерь данных?
Цадок предлагает проверенную методику, основанную на использовании аппаратного счетчика тактов процессора и битовых манипуляций.
Стоит оговориться, что регистр TSC задействовался для профилирования задолго до исследований Цадока. Данный подход детально документирован, в частности, в спецификациях Intel.
Архитектура TSC-профайлера
Алгоритм предельно прозрачен. Перед запуском целевой функции фиксируется значение аппаратного счетчика тактов процессора — TSC (Time Stamp Counter). Сразу после выполнения замер повторяется, а разница между полученными величинами определяет время выполнения операции в тактах:

Полученный результат не отправляется в поток дискретных событий, требующих экспорта и парсинга, а мгновенно агрегируется в гистограмму непосредственно на уровне ядра. Это минимизирует оверхед, поскольку вместо громоздких логов каждого вызова аккумулируется компактный массив распределения задержек.
Во избежание раздувания линейной сетки интервалов применяется логарифмическая разбивка по корзинам (buckets).
Применение побитового сдвига обеспечивает достаточную точность аппроксимации log₂, позволяя молниеносно относить измерение к определенному диапазону. На выходе формируется миниатюрная структура данных: массив из примерно 64 счетчиков (соответственно разрядности TSC). Занимаемый объем памяти не превышает одного килобайта, а накладные расходы исчисляются единичными процентами. В своем докладе Цадок упоминает около 4% на устаревших процессорах, тогда как на актуальном железе этот показатель еще ниже.
Зачем нужны такие сложности, если можно ограничиться средним арифметическим?
По той причине, что в инфраструктуре хранения операций с монолитным поведением практически не существует. Часть запросов обслуживается оперативной памятью, часть попадает в кэш контроллера, а оставшаяся доля уходит на физический накопитель.
Предположим, в вашем распоряжении имеется тысяча быстрых операций со средней латентностью 10 мкс и один аномально долгий запрос на 10 мс (вызванный промахом кэша). Этот единственный выброс существенно исказит итоговую среднюю задержку. На бимодальных либо мультимодальных распределениях классическое среднее арифметическое полностью теряет репрезентативность. Как отчетливо видно на графике ниже, гистограмма распадается на несколько обособленных пиков, и усредненное значение не описывает ни один из реальных режимов работы.

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

Цадок акцентирует внимание на том, что результаты его испытаний чувствительны ко времени проведения измерений, поэтому при анализе быстродействия критически важно изучать общую временную шкалу, а не вырванные из контекста срезы. Отсутствие графиков в динамике развязывает руки недобросовестным маркетологам, позволяя выбирать наиболее выгодные таймфрейм для подтверждения нужных тезисов.
Закон Цадока
Может сложиться ложное впечатление, будто на волне всеобщего бума искусственного интеллекта проблемы бенчмаркинга СХД утратили актуальность. Однако Цадок придерживается противоположной точки зрения, формулируя шутливый принцип собственного авторства:
«Любая вычислительная система по мере своего масштабирования неизбежно трансформируется в проблему хранения данных».
Пока веса нейросетей, KV-кэш и рабочие тензоры помещаются в сверхбыструю оперативную память, архитектура кажется реактивной. Но как только данные начинают вытесняться в системное ОЗУ, а затем и на NVMe-накопители, на арену выходят классические задачи инженеров по хранению данных. Возникают вопросы организации многоуровневого кэширования, нивелирования задержек и оптимизации миграции информации между иерархиями памяти. Красивая алгоритмическая задача неизбежно упирается в ограничения распределенного ввода-вывода.
Именно поэтому оценка производительности СХД остается востребованной дисциплиной. Чтобы четко понимать, где именно система теряет производительность, недостаточно просто активировать утилиту — важно выстроить измерительный процесс так, чтобы мониторинг не искажал объект исследования. А это значит, что инженерам по-прежнему придется оперировать корректными диаграммами размаха, агрегировать достоверные метрики и вычислять те самые микросекундные задержки, из которых складывается общая эффективность инфраструктуры. Без этой рутинной, но фундаментальной работы добиться прорыва в передовых технологических областях попросту невозможно.
Упоминания нейрослопа в соцсетях выросли почти в 20 раз
Росатом освоил производство сверхчистого германия для полупроводниковых детекторов
64% россиян поддерживают маркировку ИИ-контента
RWB Медиа открыла кабинет продвижения Wildberries в Таджикистане
Termidesk: развитие edge-вычислений повысит требования к отказоустойчивости приложений
Astra Linux Server и «Ассистент» подтвердили совместимость
Lexar показала Muse — самый тонкий внешний SSD на рынке
На орбиту вывели «всевидящее око»: новый спутник EOS-05 будет снимать Землю с высоты 36 000 км