Диск редко тормозит сам по себе - чаще тормозят неправильно выставленные параметры доступа к нему. Этот урок про слой между файловой системой и железом: как ядро ставит запросы в очередь, как поведать SSD об освобождённых блоках, чем NVMe отличается от обычного SCSI на уровне команд и как притащить блочное устройство по сети через iSCSI, чтобы оно выглядело как локальный диск. Цель - научиться видеть и крутить эти ручки осознанно, а не копипастить советы из форумов десятилетней давности.

Как это работает
Между read/write вашего приложения и пластиной диска стоит блочный слой ядра. Он группирует, переупорядочивает и склеивает запросы, а решает, в каком порядке их отдавать устройству, планировщик ввода-вывода (I/O scheduler). На HDD это критично: головка физически ездит по блинам, и упорядочивание по адресам экономит время. На SSD и NVMe никакой головки нет, любой блок одинаково близко, поэтому агрессивная сортировка только мешает.
В современном ядре (blk-mq, multi-queue) живут три планировщика. mq-deadline даёт каждому запросу дедлайн и не даёт ему голодать - универсальный выбор для HDD и SATA SSD. bfq честно делит полосу между процессами, хорош на десктопе и нагруженных HDD, но дороже по CPU. none (он же noop) вообще не переупорядочивает - то, что нужно быстрым NVMe, где у устройства своя глубокая аппаратная очередь. Планировщик виден и меняется через /sys/block/<dev>/queue/scheduler.
SSD изнашиваются: ячейка переживает ограниченное число перезаписей, а стереть можно только большими блоками. Контроллер постоянно тасует данные (wear leveling), и ему важно знать, какие блоки файловая система уже считает пустыми. Об этом сообщает команда TRIM (в терминах SCSI - UNMAP, в ATA - DISCARD). Без TRIM контроллер думает, что все когда-либо записанные блоки заняты, и со временем замедляется. Отсюда же требование выравнивания (alignment): разделы должны начинаться на границе, кратной странице/блоку стирания, иначе одна логическая запись задевает две физические страницы. Современные parted/fdisk выравнивают на 1 МиБ автоматически, так что вручную считать секторы давно не нужно.
NVMe - это не диск на шине, а протокол поверх PCIe. Вместо одной очереди SCSI у него тысячи параллельных очередей, отдельный набор команд и своя диагностика: температура, износ, лог ошибок. Поэтому им управляют не hdparm, а отдельной утилитой nvme-cli.
iSCSI заворачивает SCSI-команды в TCP/IP, и удалённый таргет (target) выглядит на вашей машине обычным /dev/sdX. Ваша сторона - инициатор (initiator), им рулит iscsiadm. Тонкость в именовании: после реконнекта или добавления дисков буква sdX может уехать, поэтому для сетевых и просто множественных дисков опираются на стабильный идентификатор WWID и симлинки в /dev/disk/by-id/ или by-path/.
Команды и примеры
Параметры SATA/IDE-диска и его кэш записи (legacy ATA, для экзамена):
Код: Выделить всё
hdparm -I /dev/sda # полная инфо: модель, поддержка TRIM, кэш
hdparm -W /dev/sda # состояние кэша записи (1 - включён)
hdparm -tT /dev/sda # грубый бенчмарк чтения (cached + buffered)
Код: Выделить всё
sdparm --all /dev/sda # все mode-страницы устройства
sdparm --get=WCE /dev/sda # Write Cache Enable
Код: Выделить всё
cat /sys/block/sda/queue/scheduler # [mq-deadline] none bfq ...
echo none > /sys/block/nvme0n1/queue/scheduler # для NVMe
Код: Выделить всё
# /etc/udev/rules.d/60-ioschedulers.rules
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", \
ATTR{queue/scheduler}="bfq"
ACTION=="add|change", KERNEL=="nvme[0-9]*", \
ATTR{queue/scheduler}="none"
Код: Выделить всё
fstrim -av # пройтись по всем смонтированным ФС
systemctl enable --now fstrim.timer # включить еженедельный прогон
NVMe через nvme-cli (пакет nvme-cli в обоих семействах):
Код: Выделить всё
nvme list # все NVMe и их размеры
nvme smart-log /dev/nvme0 # износ (percentage_used), температура
nvme id-ctrl /dev/nvme0 # фичи контроллера
Код: Выделить всё
iscsiadm -m discovery -t st -p 192.168.10.5 # найти таргеты на портале
iscsiadm -m node -T iqn.2026-06.ru.lab:disk0 -p 192.168.10.5 --login
lsblk # появился новый /dev/sdX
iscsiadm -m session # активные сессии
Код: Выделить всё
ls -l /dev/disk/by-id/ # симлинки на WWID, например wwn-0x6001...
ls -l /dev/disk/by-path/ # привязка к iSCSI-порталу
Частые грабли
- Менять планировщик через echo и удивляться, что после ребута снова дефолт - изменение в /sys временное, нужен udev-rule или ядерный параметр elevator (последний в blk-mq уже игнорируется).
- Включать discard в fstab на дешёвом SSD и ловить просадки на удалении файлов - на современных системах берите fstrim.timer.
- Гонять fstrim на тонком LVM или RAID, где нижний слой не пробрасывает discard - команда отработает вхолостую, место не освободится.
- hdparm на NVMe бесполезен, а -W/--security на чужом диске вслепую может выключить кэш или залочить накопитель - читайте, что делает ключ.
- Монтировать iSCSI-диск по /dev/sdX в fstab - после реконнекта буква уезжает, и не тот раздел монтируется не туда. Только UUID или by-id.
- Забыть _netdev для сетевого диска - systemd попытается смонтировать его до поднятия сети, загрузка повиснет или упадёт в emergency.
- Verify оборванной iSCSI-сессии без multipath: при потере линка ввод-вывод просто зависает. Для прода нужен dm-multipath, а не один путь.
- Определите тип каждого вашего накопителя: cat /sys/block/*/queue/rotational (1 - HDD, 0 - SSD/NVMe) и nvme list для NVMe.
- Посмотрите текущий планировщик для HDD и для NVMe, смените у одного на none через echo и убедитесь по cat, что применилось.
- Сделайте изменение постоянным: создайте 60-ioschedulers.rules, выполните udevadm trigger и проверьте после реальной перезагрузки.
- Проверьте поддержку TRIM (lsblk -D, столбец DISC-GRAN не ноль), запустите fstrim -av и включите fstrim.timer.
- Снимите nvme smart-log и найдите percentage_used - сколько ресурса диска уже израсходовано.
- Если есть второй хост, поднимите на нём iSCSI-таргет (targetcli), подключитесь инициатором, найдите диск в /dev/disk/by-id/ и смонтируйте его по by-id с опцией _netdev.
- Чем планировщик none предпочтительнее mq-deadline для NVMe и почему обратное верно для HDD?
- Какой файл в /sys отвечает за планировщик устройства и почему запись в него не переживает перезагрузку?
- В чём разница между периодическим fstrim и опцией монтирования discard, и что выбрать в 2026 году?
- Почему для iSCSI-дисков в fstab нельзя использовать /dev/sdX и какие стабильные имена применяют вместо него?
- Зачем при монтировании сетевого блочного устройства нужна опция _netdev?
- Какой утилитой смотрят износ и температуру NVMe и почему для этого не годится hdparm?