Производительность файловой системы: как измерить и на что влияет | AdminWiki

Производительность файловой системы: как измерить и на что влияет

17 сентября 2026 16 мин. чтения
Содержание статьи

Что такое производительность файловой системы и почему она важна

Производительность файловой системы - это набор метрик ввода-вывода, которые получает приложение, работающее через эту ФС: число операций в секунду (IOPS), пропускная способность в мегабайтах в секунду и задержка ответа в миллисекундах. Файловая система стоит между приложением и блочным устройством, поэтому один и тот же NVMe SSD под управлением ext4, XFS или ZFS с разными опциями монтирования покажет разную скорость на идентичной нагрузке.

Конкретика для начала. На одном и том же NVMe-накопителе переход с ext4 data=ordered на data=writeback даёт 20-30% прироста на записи, а смена размера блока с 4 КБ на 64 КБ меняет результат теста случайного чтения мелких файлов в пределах 30-40% в обе стороны. Это не шум измерения, а следствие того, как ФС группирует запросы, ведёт журнал и выделяет блоки.

Дальше разберём, что именно ограничивает скорость: размер кластера, фрагментацию, режим журналирования, кэширование и тип носителя. Затем - методика измерений через fio, CrystalDiskMark и штатные утилиты Linux, готовые параметры под базы данных, виртуализацию и файловый сервер, а также список мифов, которые до сих пор ломают продакшен.

Ключевые факторы, влияющие на скорость файловой системы

Факторы делятся на аппаратные и программные. Аппаратные: тип носителя, контроллер, шина, наличие батареи на кэше RAID. Программные: размер блока, опции монтирования, режим журналирования, политика кэширования в ядре, выравнивание по страйпу RAID.

Перед настройкой зафиксируйте профиль нагрузки. Две крайние точки: база данных с мелкими случайными операциями 8 КБ при глубине очереди 64 и файловое хранилище с последовательным чтением блоками 1 МБ. Первый сценарий упирается в IOPS и задержку, второй - в пропускную способность. Параметры, которые ускоряют один профиль, часто замедляют другой: поведение ext4, XFS, Btrfs и ZFS на разных нагрузках разобрано в материале про сравнение производительности файловых систем.

Размер кластера файловой системы: как выбрать и на что влияет

Кластер (блок) - минимальная единица, которую ФС выделяет файлу. Файл размером 900 байт всё равно займёт один блок, поэтому блок 4 КБ потратит впустую около 3 КБ, а блок 64 КБ - больше 63 КБ.

Значения по умолчанию: ext4 - 4 КБ, XFS - 4 КБ на x86_64 (размер блока ограничен размером страницы ядра), NTFS - 4 КБ для томов до 16 ТБ, ZFS вместо блока использует recordsize со значением 128 КБ и переменный размер блоков внутри датасета.

Как размер блока меняет скорость. Крупный блок снижает число операций на тот же объём данных, поэтому последовательная запись блоками 1 МБ растёт. Мелкий блок выгоден на мелких файлах: чтение файла 2 КБ с блоком 4 КБ займёт одну операцию, а с блоком 64 КБ тоже одну, но с диска будет прочитано 64 КБ. Лишние 62 КБ увеличивают задержку, износ и нагрузку на кэш, на HDD это заметно сильнее из-за медленного позиционирования головки.

Практические рекомендации: базы данных - 4 КБ (совпадает с размером страницы PostgreSQL и InnoDB), виртуальные машины - 4-16 КБ, файловый сервер с крупными файлами - 64 КБ там, где ФС это позволяет. Для ZFS настраивают recordsize: 16 КБ под ВМ и СУБД, 1 МБ под медиатеку и бэкапы.

Ограничение, о котором забывают: размер блока задаётся при создании ФС и не меняется без пересоздания. На Linux с 4 КБ страницей XFS не получит блок 64 КБ, там работают через экстенты и выравнивание: mkfs.xfs -f -b size=4096 -d su=512k,sw=8 /dev/nvme0n1p1. Параметры su и sw выравнивают ФС по страйпу RAID и дают до 10-15% на записи против неверного выравнивания.

Фрагментация файловой системы: причины, последствия и борьба

Фрагментация бывает двух видов: файловая (один файл разбросан по разным областям диска) и фрагментация свободного пространства (свободные блоки разбиты на мелкие куски, новый файл нельзя разместить непрерывно).

На HDD последствия прямые: растёт время поиска, головка прыгает между дорожками, последовательное чтение превращается в случайное, пропускная способность падает со 150 МБ/с до 30-50 МБ/с. На SSD фрагментация почти не влияет на скорость чтения, но увеличивает объём метаданных и число обращений к таблице трансляции, а также ускоряет износ ячеек.

ext4 и XFS борются с ней экстентами (непрерывными диапазонами блоков) и отложенным выделением: свободное место резервируется под запись пачкой, а не по одному блоку. Помогает не всегда. Если раздел заполнен на 95%, непрерывных областей не остаётся, и ФС начинает дробить файлы.

Что делать: держать занятость раздела в пределах 80-85%, для крупных файлов брать XFS или ZFS, на SSD включить TRIM. Вариантов два: опция монтирования discard (команда TRIM идёт сразу при удалении блока файла) или таймер fstrim раз в неделю. Второй предпочтительнее, discard даёт всплески задержек при массовом удалении файлов. На ext4 для HDD уместна дефрагментация через e4defrag, на XFS - через xfs_fsr. На SSD дефрагментация вредна: перемещения блоков тратят ресурс ячеек и не дают прироста скорости.

Режим журналирования ext4: data=ordered, writeback, journal

ext4 ведёт журнал метаданных, а режим монтирования data= определяет, что ещё в него попадает.

data=journal: журналируются и метаданные, и данные. Самый надёжный вариант, после сбоя восстанавливается содержимое файлов, и самый медленный: каждое изменение пишется дважды. На случайной записи просадка относительно ordered достигает 1,5-2 раз.

data=ordered (режим по умолчанию): в журнал идут только метаданные, но данные попадают на диск до фиксации метаданных. Так исключаются «нулевые» хвосты в файлах после сбоя, а накладные расходы умеренные. Этот режим стоит держать на большинстве серверов.

data=writeback: в журнал идут только метаданные, порядок записи данных не гарантируется. Прирост на записи 20-30%, но после внезапного отключения питания файл может содержать старые данные там, где приложение уже записало новые. Годится для временных каталогов, кэшей сборок и логов, не годится для данных, которые нельзя восстановить.

Смежные параметры. commit=60 увеличивает интервал сброса журнала с 5 до 60 секунд: запись идёт плавнее, окно потери данных растёт до минуты. Опция barrier на современных ядрах заменена командами flush/FUA, её отключение равносильно отказу от гарантий записи. В XFS такой гибкости нет: журнал всегда хранит только метаданные, а надёжность синхронных операций определяют через атрибуты и sync. У ZFS аналог журнала - ZIL с режимами sync=standard и sync=always.

Кэширование: page cache, кэш контроллера и его влияние на тесты

Page cache в Linux хранит недавно прочитанные и ещё не записанные страницы. Приложение читает файл второй раз и получает данные из памяти за микросекунды, диск не задействован. Отсюда главная ошибка бенчмарков: тест на файле 1 ГБ при 64 ГБ RAM измеряет память, а не накопитель.

Как обойти кэш. Первый способ - прямой ввод-вывод (O_DIRECT), в fio это direct=1, в dd - oflag=direct. Второй - сброс кэша перед замером командой echo 3 > /proc/sys/vm/drop_caches. Для тестов применяйте первый: он воспроизводим и не требует root.

Кэш RAID-контроллера. Запись в кэш с батареей возвращается приложению сразу, не дожидаясь вращения дисков, и на синхронных операциях ускоряет отклик в разы. Без батареи контроллер обязан работать в режиме сквозной записи, иначе при потере питания данные исчезнут. При тестировании без BBU цифры окажутся заметно хуже ожидаемых, и это нормальное поведение железа.

Грязные страницы ядра. Параметры vm.dirty_ratio и vm.dirty_background_ratio задают долю RAM под не сброшенные на диск данные. Значения по умолчанию 20% и 10% на сервере с 256 ГБ памяти означают до 51 ГБ грязных страниц, а их сброс даёт приложению всплеск задержки в десятки миллисекунд. Для СУБД ставьте dirty_background_ratio 5-10% и dirty_ratio 10-15%, а на быстрых NVMe ограничивайте сброс в мегабайтах через vm.dirty_bytes и vm.dirty_background_bytes.

Тип носителя: HDD, SATA SSD, NVMe SSD

НосительСлучайные IOPSЗадержкаПоследовательная пропускная способность
HDD 7200 rpm100-2005-15 мс100-250 МБ/с
SATA SSD50 000-100 0000,1-0,2 мсдо 550 МБ/с
NVMe SSD PCIe 4.0500 000-1 000 0000,02-0,1 мс3-7 ГБ/с

На HDD подбор параметров ФС даёт единицы процентов, переход на SSD ускоряет случайные операции в сотни раз. Это главный приоритет при модернизации: сначала носитель, потом тюнинг.

SATA SSD ограничен интерфейсом 6 Гбит/с, для него включайте TRIM и проверяйте, что контроллер работает с NCQ: без очереди команд случайные операции теряют до половины производительности. NVMe требует другого подхода: планировщик ввода-вывода none или mq-deadline, много очередей, асинхронный ввод-вывод через io_uring. На NVMe узкое место часто смещается в ядро, файловую систему и само приложение, а не в накопитель.

Как измерить производительность файловой системы: методика и инструменты

Методика состоит из пяти шагов. Определите профиль нагрузки: доля чтения и записи, размер блока, глубина очереди, число параллельных потоков. Выберите инструмент под задачу. Снимите базовые метрики на текущей конфигурации. Примените изменение. Повторите тест и сравните цифры.

Тестирование на рабочем сервере срывает SLA: fio с высокой глубиной очереди забивает очереди блочного устройства, а задержки для пользователей растут в разы. Для бенчмарков берите отдельный стенд, при отсутствии железа подойдёт облачный сервер с NVMe-диском, например у Timeweb Cloud. На SSD тест с интенсивной записью расходует ресурс ячеек: серия прогонов по 4 ТБ съедает ощутимую долю TBW, поэтому не гоняйте один и тот же тест десятками итераций.

fio: гибкий инструмент для нагрузочного тестирования

fio измеряет IOPS, пропускную способность и задержку одновременно и воспроизводит любой профиль. Пример случайного чтения 4 КБ с глубиной очереди 32 в четырёх потоках:

fio --name=randread --ioengine=libaio --direct=1 --rw=randread --bs=4k --numjobs=4 --iodepth=32 --size=1G --runtime=60 --time_based --group_reporting --lat_percentiles=1 --percentile_list=50:99:99.9

Пример последовательной записи блоком 1 МБ:

fio --name=seqwrite --ioengine=libaio --direct=1 --rw=write --bs=1M --numjobs=1 --iodepth=16 --size=4G --runtime=60 --time_based --group_reporting

Ключевые параметры: ioengine задаёт механизм ввода-вывода, direct=1 отключает page cache, rw выбирает профиль (randread, randwrite, randrw, read, write), bs - размер блока, iodepth - глубину очереди, numjobs - число параллельных задач, time_based с runtime включает работу по времени вместо фиксированного объёма.

В выводе смотрите три блока: iops и bw (пропускная способность в МиБ/с) по чтению и записи, lat (msec) со средним значением, и clat percentiles, где важнее всего 99-й и 99,9-й перцентиль. Для баз данных запускайте randread и randwrite с bs=8k-16k и iodepth 32-128, для файлового сервера - read и write с bs=128k-1M и малой глубиной очереди. Перед замером на SSD сделайте предварительное заполнение: запишите объём, равный удвоенной ёмкости диска, иначе SLC-кэш завысит результат в разы.

CrystalDiskMark как пользоваться: пошаговая инструкция

Интерфейс простой: выберите диск, число прогонов, размер тестового файла и профиль. Значимые профили: SEQ1M Q8T1 (последовательные 1 МБ, очередь 8, один поток), SEQ1M Q1T1, RND4K Q32T16 (случайные 4 КБ, очередь 32, 16 потоков) и RND4K Q1T1. Первые два показывают пиковую пропускную способность, третий - IOPS, четвёртый - задержку в одиночном потоке, то есть отклик для интерактивных задач и настольных систем.

Правила запуска: не меньше 5 прогонов, размер тестового файла от 1 ГБ, занятость диска 50-80%. Пустой накопитель с включённым SLC-кэшем покажет цифры, которых на реальной нагрузке не будет. Для SATA SSD ориентируйтесь на QD32, для NVMe имеет смысл QD64 и выше.

Программа работает в Windows; в Linux её запускают через Wine, но для серверов это лишний слой, надёжнее fio. Одинаковые профили по умолчанию делают CrystalDiskMark удобным для быстрого сравнения нескольких NVMe на одном стенде, а интерпретация цифр на серверных нагрузках разобрана в статье про поиск узкого места в файловом хранилище.

Встроенные средства ОС: iostat, dd, sar

iostat -x -m 1 выдаёт по каждому устройству: r/s и w/s (операции в секунду), rkB/s и wkB/s (пропускная способность), r_await и w_await (средняя задержка с учётом очереди), aqu-sz (средняя длина очереди) и %util (доля времени, когда устройство занято). Ориентиры: %util выше 80% на HDD и выше 90% на SSD говорит о насыщении, а рост aqu-sz при неизменной нагрузке означает, что подсистема не успевает.

iostat -x -m 1
dd if=/dev/zero of=/mnt/test.bin bs=1M count=4096 oflag=direct status=progress
dd if=/mnt/test.bin of=/dev/null bs=1M iflag=direct status=progress

dd годится для быстрой проверки: он покажет пропускную способность, но не даст ни IOPS, ни задержку, ни распределение. sar -d 1 собирает ту же статистику и хранит историю в /var/log/sa, что помогает сравнить состояние до и после изменения без повторного теста. Для задержки одиночных операций удобен ioping: ioping -c 20 -s 4k /mnt. Полный набор команд и пороговых значений для диагностики сервера собран в материале про мониторинг производительности сервера.

Какие метрики важны в каждом сценарии: IOPS, пропускная способность, задержка

IOPS решают там, где много мелких случайных операций: PostgreSQL, MySQL, MariaDB, диски виртуальных машин, очереди сообщений. Пропускная способность важна для файловых серверов, бэкапов, потокового видео и выгрузки аналитики. Задержка критична для интерактивных сервисов и СУБД: смотрите не среднее значение, а 99-й и 99,9-й перцентиль, потому что именно всплески формируют жалобы пользователей.

Ориентиры для планирования: PostgreSQL комфортно работает при задержке записи до 1-2 мс на p99, веб-сервер с кэшем переживает 10 мс, интерактивный аналитический запрос с сортировкой 5 ГБ требует пропускной способности 1-2 ГБ/с, чтобы уложиться в разумное время. Смешанная нагрузка проверяется отдельным прогоном с --rw=randrw --rwmixread=70. Как пересчитать требования приложения в конфигурацию RAID и дисков, показано в руководстве про расчёт производительности СХД.

Настройка файловой системы под конкретные задачи

Рекомендации ниже проверены на серверных нагрузках и подходят для ядер 6.x и дистрибутивов 2025-2026 годов с ext4, XFS и ZFS. Опции монтирования прописывайте в /etc/fstab, а не разовой командой: после перезагрузки разовая настройка исчезнет.

Базы данных: PostgreSQL, MySQL, MariaDB

Выбор ФС: XFS или ext4. ZFS под СУБД даёт снапшоты и контрольную сумму блоков, но требует памяти под ARC и аккуратной настройки recordsize, поэтому на одиночном сервере баз данных чаще берут XFS.

XFS: блок 4 КБ, опции noatime,nodiratime,logbufs=8,logbsize=256k, выравнивание по страйпу RAID через su и sw. Лог XFS размером 2-4 ГБ размещайте на быстром носителе.

ext4: блок 4 КБ, data=ordered, noatime,nodiratime, commit=5-15. Отключение atime убирает запись метаданных при каждом чтении файла, на каталоге с миллионом обращений в сутки это тысячи лишних операций в час.

PostgreSQL: каталог pg_wal выносите на отдельный NVMe с XFS и блоком 4 КБ, данные - на второй NVMe или RAID10. Синхронный коммит требует честного fsync, поэтому кэш контроллера без батареи и отключённые сбросы дадут рост скорости и риск повреждения кластера после сбоя питания.

MySQL и MariaDB: innodb_flush_method=O_DIRECT снимает двойное кэширование (буферный пул InnoDB плюс page cache), innodb_io_capacity выставляют по фактическим IOPS носителя. Для SATA SSD включайте fstrim.timer, для NVMe проверьте, что планировщик установлен в none.

Виртуализация: KVM, VMware, Proxmox

XFS: блок 4 КБ, опции noatime,nodiratime, опция allocsize=1m снижает фрагментацию образов. Для KVM образы в формате raw читаются быстрее, чем qcow2, но не поддерживают снапшоты уровня файла, а на XFS файловых снапшотов нет. Нужны снапшоты - берите ZFS или LVM.

ZFS: recordsize=16k под виртуальные машины с мелкими операциями, compression=lz4 (сжатие включайте даже на быстрых дисках, оно уменьшает объём фактической записи), atime=off, для zvol ставьте volblocksize=16k. Планируйте память: ориентир 1 ГБ RAM на 1 ТБ данных описывает ARC, при 32 ГБ памяти на хосте ограничивайте кэш через zfs_arc_max.

Proxmox: локальное хранилище на XFS с noatime закрывает задачи большинства стендов, ZFS с L2ARC и SLOG оправдан при сотнях ВМ и требовании снапшотов. Для Hyper-V и VHDX на NTFS используйте единицу выделения 64 КБ, для каталогов с мелкими файлами внутри ВМ - 4 КБ. Если нужен стенд под замеры, дешевле арендовать сервер в облаке, чем собирать физическую конфигурацию: порядок подбора ресурсов под нагрузку описан в статье про выбор системы хранения.

Файловый сервер: NFS, SMB, TrueNAS

XFS: блок 4 КБ, опции noatime,nodiratime,inode64, а под каталоги с медиафайлами задайте крупный экстент через xfs_io -c "extsize 256m". Напомню, что на x86_64 блок XFS выше 4 КБ не поднять, ограничение задаёт размер страницы ядра, поэтому крупные объёмы записи ускоряют именно экстентами.

ZFS: recordsize=1M для медиатеки и архивов, compression=lz4, atime=off. Сжатие lz4 на текстовых данных, логах и JSON даёт экономию места 30-50% при минимальной нагрузке на CPU. Для датасета с домашними каталогами пользователей оставляйте recordsize 128 КБ.

Сеть влияет не меньше файловой системы. NFS: rsize и wsize 1 МБ, опция nconnect=4 для нескольких TCP-соединений на один mount, версия 4.2 с серверным копированием. SMB: минимум SMB3, multichannel, на RDMA-стендах SMB Direct, размер блока 1 МБ. На TrueNAS с ZFS под медиатеку создают датасет с recordsize=1M, под виртуальные машины - с recordsize=16k.

Мифы и ошибочные параметры, снижающие скорость

«Чем больше блок, тем быстрее». На последовательной записи это верно, на случайном чтении - нет. Файл 2 КБ на блоке 64 КБ заставит прочитать 64 КБ с диска: лишний трафик, рост задержки и ускоренный износ. Для каталога из 200 тысяч мелких файлов блок 64 КБ даст перерасход места в десятки раз без прироста скорости.

«Отключим журнал, будет быстрее». Отключение журнала ext4 даёт 10-20% на записи, но после сбоя e2fsck проверяет весь раздел: на томе 10 ТБ это часы простоя, а структура каталогов может пострадать необратимо. Для баз данных такой компромисс недопустим.

«SSD надо дефрагментировать». Нет. Контроллер сам раскладывает блоки по чипам для параллелизма, дефрагментация только тратит ресурс ячеек и ничего не ускоряет.

«noatime не нужен, разница копеечная». На файловом сервере с миллионом чтений в сутки строгий atime добавляет столько же записей метаданных. Замер на почтовом хранилище: переход на noatime сократил объём записи на 15-20%.

«barrier=0 и nobarrier ускоряют диск». Ядро отдаёт команды flush и FUA, их отключение оставляет кэш контроллера буфером без гарантий. Практический случай: PostgreSQL на ext4 с отключёнными сбросами после отключения питания получил повреждённый WAL, восстановление заняло несколько часов вместо минуты.

«swappiness=0 ускоряет сервер». Параметр управляет вытеснением анонимных страниц. Ноль оставляет ядру слишком мало свободы при нехватке памяти, и вместо управляемого свопа вы получаете срабатывание OOM-killer. Для СУБД рабочее значение 1-10.

«discard в опциях монтирования всегда лучше fstrim». Постоянный discard отправляет TRIM при каждом удалении блока и даёт всплески задержки при массовых операциях. Периодический fstrim раз в неделю даёт тот же эффект по износу без просадок отклика.

Как безопасно применять изменения и проверять результат

Порядок действий, который снижает риск сломать рабочую систему.

  1. Снимите базовые метрики: fio по своему профилю плюс iostat -x -m 1 в течение рабочего дня. Без исходных цифр вы не докажете эффект изменения.
  2. Сделайте резервную копию или снапшот: zfs snapshot, lvcreate -s для LVM, полный бэкап с проверкой восстановления для bare-metal.
  3. Проверьте изменение на тестовом стенде с той же конфигурацией дисков и RAID. Виртуальная машина не покажет эффект выравнивания и кэша контроллера.
  4. Применяйте в окно обслуживания. Часть параметров требует перемонтирования (data=, noatime, commit), часть - только пересоздания ФС.
  5. Повторите тесты и сравните с базовыми. Разница меньше 5% на одном прогоне может быть шумом, делайте 3-5 итераций.
  6. Наблюдайте 3-7 дней: iostat, задержку p99 в мониторинге, записи об ошибках ввода-вывода в dmesg, атрибуты износа в SMART.

Что нельзя менять на живой системе. Размер блока, тип ФС и размер журнала XFS требуют mkfs: данные будут потеряны. Режим data= переключается только на размонтированной ФС, потому что меняет поведение журнала. tune2fs умеет выключать и включать журнал или менять интервал сброса, но такие операции на смонтированном разделе повышают риск повреждения. Параметры ядра (dirty_ratio, планировщик ввода-вывода) применяются на лету через sysctl и запись в /sys, но закрепите их в /etc/sysctl.d и в правилах udev, иначе после перезагрузки они пропадут.

После сбоя питания не спешите монтировать раздел на запись. ext4 с журналом восстановится сам, XFS проигрывает лог при монтировании. Если монтирование не проходит, запустите xfs_repair -n для проверки без изменений и только затем xfs_repair. Для ext4 принудительная проверка выполняется как e2fsck -f на размонтированном устройстве. Раздел, помеченный ядром как errors=remount-ro, проверяйте целиком, а не возвращайте в работу на веру.

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

Поделиться:
Сохранить гайд? В закладки браузера