Кэши, режимы нагрузки и ловушка среднего: почему storage-бенчмарки вводят в заблуждение
Представьте типичную ситуацию: разработчики добавили прозрачное шифрование в файловую систему, пересобрали ядро и запустили FIO. Пропускная способность осталась на прежнем уровне. После внедрения изменений в промышленную среду производительность, однако, заметно снизилась. На первый взгляд кажется, что тест оказался неверным. Но на самом деле он честно измерил предел дисковой подсистемы, тогда как дополнительные расходы на шифрование скрылись за задержками медленного накопителя.
Это один из наиболее распространённых сценариев, показывающих, почему обычное тестирование производительности дисков далеко не всегда отражает поведение системы в реальной эксплуатации. Хранилище нельзя свести к простой связке "файловая система - блочное устройство - throughput". Между приложением и физическим носителем работают кэши, планировщики, виртуальные слои, сетевые протоколы, программные RAID-массивы и механизмы копирования данных между ядром и пользовательским пространством.
Чтобы понять особенности измерений, полезно обратиться к подходам Эреза Цадока, профессора Университета Стони-Брук и руководителя лаборатории файловых систем и хранения данных. Его исследования хорошо показывают: результат зависит не только от оборудования, но и от того, какой участок стека, каким запросом и в каком режиме мы проверяем.
Storage - это не один уровень
Современную систему хранения удобно представлять в виде многоуровневой конструкции. Внизу находятся относительно дешёвые и медленные HDD, выше - SSD, кэши операционной системы, оперативная память, процессорные кэши и регистры. Разница между самой быстрой и самой медленной операцией может составлять от четырёх до восьми порядков.
При этом реальный storage stack давно перестал быть строгой иерархией. К нему подключаются LVM, программные RAID, виртуальные машины, NFS, сетевые адаптеры и дополнительные сервисы. В системах с пользовательскими файловыми системами появляются ещё и переключения контекста, передача данных между kernel space и user space, а также копирование буферов.
Поэтому даже качественный бенчмарк SSD накопителей способен показывать лишь производительность конкретной конфигурации и конкретного сценария. Если приложение обращается к данным иначе, результат может измениться в разы.
С прозрачным шифрованием это видно особенно хорошо. Допустим, файловая система с дополнительной обработкой выдаёт 150 МБ/с, а вариант без шифрования - те же 150 МБ/с. Нельзя сразу делать вывод, что шифрование не создаёт накладных расходов. Возможно, система работает в режиме I/O bound: пока накопитель обслуживает операции, процессор успевает выполнить криптографические вычисления практически без влияния на итоговую скорость.
На быстрой NVMe-системе ситуация изменится. Накопитель перестанет быть главным ограничением, а узким местом станет CPU. Та же операция шифрования, которая на HDD выглядела "бесплатной", начнёт уменьшать пропускную способность. Именно поэтому [корректное измерение производительности систем хранения](https://habr.com/ru/companies/garda/articles/1077526/?utm_campaign=1077526&utm_source=habrahabr&utm_medium=rss) требует проверять несколько аппаратных конфигураций и режимов нагрузки.
Почему dd часто показывает не то
Расхождение между результатом теста и поведением приложения характерно не только для синтетических инструментов. Показательный пример - запись через `dd` на блочное устройство.
Обычно `dd` выполняет последовательную запись одним потоком и крупными блоками. Если явно не использовать `fsync` или соответствующие параметры, команда может завершить работу после помещения данных в page cache. В этот момент операционная система ещё продолжает сбрасывать информацию на накопитель, а пользователь уже видит впечатляющую скорость.
База данных создаёт совершенно иной профиль. Она выполняет случайные операции, читает нужные страницы, обновляет записи, журналы и индексы, синхронизирует транзакции и часто требует гарантии устойчивой записи. Поэтому те же диски, которые демонстрируют в `dd` 500 МБ/с последовательной записи, в рабочем сценарии базы данных могут обеспечивать лишь 100-200 МБ/с либо упираться в задержки и количество IOPS.
Для оптимизации производительности хранилища данных важно измерять не абстрактную скорость устройства, а поведение всей цепочки: от системного вызова приложения до физической фиксации данных.
Опасность среднего значения
Даже правильно выбранная нагрузка не гарантирует корректных выводов. Одна из главных ловушек - использование среднего времени отклика. Среднее значение может выглядеть стабильным, хотя часть запросов уже испытывает серьёзные задержки.
Например, 99 операций могут завершаться за 1 мс, а одна - за 1 секунду. Среднее значение составит около 11 мс, но для пользователя, которому достался медленный запрос, система будет выглядеть крайне неэффективной. В интерактивных сервисах, базах данных и распределённых системах такие редкие задержки могут запускать каскадные тайм-ауты.
Поэтому в отчётах следует отображать медиану, 90-й, 95-й, 99-й и 99,9-й перцентили, а также максимальные значения. Не менее важно строить графики во времени: усреднение за весь прогон способно скрыть прогрев кэша, периодические сбросы dirty pages, фоновые операции RAID или кратковременные перегрузки сети.
Кэш может превратить тест в фикцию
Кэширование - ещё одна причина, по которой показатели оказываются завышенными. Повторное чтение одних и тех же блоков может происходить из оперативной памяти, а не с диска. В результате тест якобы измеряет скорость памяти и работы файловой системы, хотя исследователь думает, что проверяет накопитель.
Чтобы отделить уровни системы, нужно заранее определить цель эксперимента. Если измеряется устройство, необходимо учитывать page cache и при необходимости очищать его между запусками. Если же проверяется реальное приложение, кэш, наоборот, должен оставаться частью сценария: именно так система работает в боевой среде.
Большое значение имеет и прогрев. Первые секунды теста могут показывать один результат, а после заполнения кэшей, выхода на устойчивую температуру или включения фоновой сборки мусора - совершенно другой. Поэтому короткий единичный запуск редко бывает достаточным.
Как строить достоверный эксперимент
Хорошая методика начинается с формулировки вопроса. Нужно заранее решить, что именно измеряется: максимальная последовательная скорость, случайный доступ, задержка отдельного запроса, пропускная способность при параллельной нагрузке или влияние конкретного изменения в файловой системе.
После этого фиксируются параметры эксперимента:
- размер блока;
- глубина очереди;
- число потоков;
- соотношение чтения и записи;
- синхронный или асинхронный режим;
- состояние кэшей;
- длительность прогона;
- температура накопителя;
- фоновая активность системы;
- используемые файловая система и слой виртуализации.
Для таких задач FIO остаётся одним из наиболее гибких инструментов, но сам по себе он не делает эксперимент правильным. Неверный профиль нагрузки даст точный ответ на неправильный вопрос. Поэтому FIO тестирование дисковой подсистемы должно сопровождаться мониторингом CPU, памяти, очередей I/O, задержек, page cache и сетевых интерфейсов.
Нужно также разделять нагрузочный и диагностический этапы. Сначала выполняется длительный прогон до выхода системы на стабильный режим, затем собирается статистика. После этого отдельно анализируются выбросы и моменты деградации. Если ограничиться одной итоговой цифрой, можно не заметить, что средний результат получен за счёт коротких периодов высокой скорости между регулярными провалами.
Производительность файловой системы нельзя сводить к скорости диска
Файловая система влияет на результат через метаданные, журналирование, аллокаторы, блокировки, порядок записи и работу с кэшами. Для небольших файлов важнее могут оказаться операции с каталогами и inode, а не пропускная способность самого накопителя. При большой параллельной нагрузке ограничением становится конкуренция потоков или глобальные блокировки.
Именно поэтому производительность файловой системы должна проверяться несколькими сценариями: последовательным и случайным доступом, созданием и удалением большого числа файлов, параллельными операциями, чтением уже закэшированных данных и работой с файлами, размер которых превышает объём доступной памяти.
В итоге достоверный storage-бенчмарк - это не одна красивая цифра и не максимальный показатель из рекламного отчёта. Это воспроизводимый эксперимент с понятной нагрузкой, контролируемыми условиями, распределением задержек и анализом узких мест. Чем сложнее система - от локального NVMe до сетевого кластера с виртуализацией, - тем опаснее делать выводы по среднему throughput. Только сопоставление синтетических тестов с профилем реального приложения позволяет понять, где находится настоящее ограничение и даст ли оптимизация ожидаемый эффект.


