Вибір планувальника IO для ZFS: mq-deadline чи none для HDD, SSD і NVMe

Було корисно?

У вас є пул ZFS, який під час тестів у спокійний день показує нормальну продуктивність, а о 2:00 ночі перетворюється на гарбуз.
Scrub-и повзають. Затримки підіймаються. База даних починає таймаути, а всі пильно дивляться на “%util”, ніби вона має зізнатися.
Десь у стеку Linux IO планувальник або допомагає… або ввічливо робить ще гірше.

Висновок: у випадку ZFS ви не стільки «налаштовуєте планувальник», скільки запобігаєте його конфлікту з рештою системи.
Це стаття для прийняття рішення: що встановлювати для HDD, SATA/SAS SSD і NVMe; як це довести командами; і як діагностувати
моторошні режимы відмов, коли реальність не відповідає припущенням.

Правило в одному реченні (що встановити)

Якщо вам потрібен дефолт, який витримає контакт з продакшеном: використовуйте mq-deadline для ротаційних дисків і більшості SATA/SAS SSD,
а none — для NVMe (та інших висококласних пристроїв з власними глибокими апаратними чергами).

Це базова рекомендація. Відхиляйтеся від неї тільки якщо можете пояснити, на основі вимірювань, що саме ви оптимізуєте: хвостову затримку, справедливість між завданнями
або конкретну особливість пристрою/драйвера.

Що насправді роблять планувальники IO в blk-mq

Планувальник IO не є «перемикачем режиму продуктивності». Це політичний механізм між блочним шаром і драйвером пристрою,
який вирішує, як відсортовуються, зливаються і відправляються запити. На сучасному Linux більшість блочних пристроїв використовують
багаточерговий блочний шар (blk-mq), що змінює історію планувальників у порівнянні зі старою ерою з однією чергою.

blk-mq змінив проблему: від одного ліфту до багатьох смуг

Класичні «ліфтові» планувальники (deadline, CFQ, noop) були побудовані для однієї черги запитів, що живить одну апаратну чергу.
blk-mq додає кілька програмних черг відправлення (часто по CPU), які мапляться на одну або більше апаратних черг відправки. Планувальник тепер може працювати
в контексті апаратного потоку, а сам пристрій може робити агресивний реордеринг (NVMe в цьому плані особливо хороші).

Практично це означає: якщо апарат уже виконує глибоке чергування і «розумне» відправлення, додаткова прошаркова «майстерність» у програмі може
підвищити варіативність затримок і споживання CPU без приросту пропускної здатності.

mq-deadline: обмежене очікування і «не голодувати читання»

mq-deadline — це версія deadline для blk-mq. Він тримає окремі черги для читань і записів, відстежує часи прострочення
і відправляє запити так, щоб уникати голодування. Також виконує злиття запитів коли можливо.

На ротаційному носії це має значення. HDD мають жахливу випадкову затримку; якщо дозволити записам накопичуватися нескінченно, читання можуть загинути, і ваш додаток
інтерпретує це як «диск помер». Deadline намагається обмежити шкоду. На SATA SSD він також може допомогти, згладжуючи сплески та утримуючи
затримки від перетворення на дику поведінку під змішаними навантаженнями.

none: «руки геть» (але не «без чергування»)

none означає, що блочний шар виконує мінімальне планування понад те, що безпосередньо робить blk-mq. Запити все ще ставляться в чергу — просто без
додаткової політики «ліфта». Це зазвичай краще для NVMe тому що:

  • NVMe-пристрої мають кілька апаратних черг і складні внутрішні планувальники.
  • NVMe віддає перевагу паралелізму; додаткове програмне впорядкування може зменшити конкурентність.
  • Навантаження CPU важливе при високих IOPS; «none» зменшує роботу планувальника.

Чому не BFQ, kyber або «той дефолт, що є»?

BFQ і kyber існують з вагомих причин. BFQ може бути відмінним для інтерактивності робочого столу й забезпечення справедливості; kyber орієнтований на контроль затримок під навантаженням.
Але ZFS вже має свої власні IO-патерни й механізми буферизації, і для багатьох продакшен-робочих навантажень ZFS важливіше передбачувана хвостова затримка
та уникнення патологічних взаємодій, ніж справедливість на рівні cgroup.

Якщо ви працюєте на хостах з кількома орендарями, де сувора справедливість критична, варто їх розглянути. Але для звичного сценарію «ZFS-пул для БД,
VM, NFS, об’єктного сховища або бекапів» mq-deadline/none — це здоровий початок. Частіше правильний крок — не «кращий планувальник», а «припинити подвійне планування і вимірювати затримки правильно».

Як ZFS змінює правила гри (ARC, TXG, sync і чому «більше планування» не завжди краще)

ZFS — не тупий споживач блоку. Це файловий менеджер і менеджер томів, який уже виконує агрегацію, впорядкування і формування поведінки записів.
Коли кажуть «ZFS любить послідовні записи», на практиці мають на увазі: ZFS докладає зусиль, щоб перетворити розкидані записи додатка на більші,
більш суміжні IO під час коміту.

Записи ZFS стадіюються: «серцебиття» TXG

ZFS групує модифікації в transaction groups (TXG). Брудні дані накопичуються в пам’яті, потім ZFS комітить їх на диск. Це батчування чудово підвищує пропускну здатність і стиснення,
і воно також відповідає за те, чому «додаток записав 4 KB, а диск виконав 1 MB» — це не містика, а ZFS, що працює ефективно.

Планувальник бачить кінцевий блоковий IO-патерн, а не намір додатка. Якщо ви додаєте агресивне переставляння на рівні планувальника, ви можете заважати спробам ZFS керувати затримками для читань під час скидання записів.

Sync-записи: місце, де припущення вмирають

Для sync-записів ZFS має гарантувати збереження перед підтвердженням завершення (залежно від налаштувань і характеру навантаження). Якщо у вас немає окремого SLOG-пристрою,
ваше sync-навантеження може перетворитися на «випадкові затримки запису — ваша нова реальність».

Жоден планувальник IO не врятує вас від пулу HDD, який виконує малі sync-записи без журналу. Він лише може вплинути на те, наскільки болісно відчувається чекання.

Поводження читань ZFS: prefetch і metadata

ZFS робить prefetch і адаптивне кешування (ARC). Багато читань обслуговуються з RAM; ті, що доходять до диска, часто є інтенсивними за метаданими, випадковими або викликані scrub/resilver.
Тому вибір «планувальника» має віддавати пріоритет запобіганню вибухів хвостової затримки, коли диск завантажений.

Подвійне чергування і «податковa затримка»

ZFS чергує IO внутрішньо. Блочний шар чергує IO. Прошивка пристрою чергує IO. Це три місця, де затримка може ховатись, і під тиском вона любить множитися.

Якщо ваш пристрій — NVMe з глибокими чергами, додавання mq-deadline може підвищити варіативність затримок, переставляючи запити, які контролер міг би
краще обробити паралельно. Якщо ж пристрій — HDD, залишення на «none» може дозволити патологічним шаблонам голодування, які ZFS не завжди може згладити.

Парафразована ідея (Werner Vogels, reliability/operations): «Все рано чи пізно ламається; ви проектуєте системи, виходячи з цього.»
Вибір планувальника — саме такий підхід: оберіть політику, яка дає найменше поганий результат під некрасивим навантаженням.

Рекомендації за типом носія: HDD vs SATA/SAS SSD vs NVMe

Ротаційний HDD (окремі диски, дзеркала, RAIDZ)

Використовуйте mq-deadline.

HDD — це машини затримки з хобі робити IO. При змішаних навантаженнях (scrub + читання + запис) HDD може голодувати читання, поки обробляє записи.
mq-deadline дає практичну гарантію: читання не стоятимуть за записами вічно.

Коли розглядати інші варіанти? Переважно коли у вас спеціалізований пристрій або ви валідовано показали, що інший планувальник (наприклад kyber)
дає кращу хвостову затримку під вашим точним навантаженням. Але для загального ZFS на Linux з HDD vdevs mq-deadline — нудно, але правильна відповідь.

SATA/SAS SSD (споживчі або корпоративні)

За замовчуванням — mq-deadline, розглядайте none лише якщо маєте докази, що це допомагає, і SSD не «погано поводиться».

SATA/SAS SSD дуже різняться. Деякі мають адекватне внутрішнє планування; інші «провалюються» під час garbage collection або коли політики кешу запису взаємодіють з захистом від втрати живлення (або її відсутністю).

mq-deadline часто робить затримки більш передбачуваними на SATA SSD під змішаними читання/запис або при стрибкоподібній поведінці flush, що добре корелює з TXG-флашами ZFS.
«none» теж може бути прийнятним — особливо для корпоративних SSD з міцною прошивкою — але не припускайте, що правила для NVMe застосовні автоматично.

NVMe (PCIe)

Використовуйте none.

NVMe створено для паралельних черг, а не для ставлення як до «фантазійного SATA-диска». Контролер уже приймає рішення про відправлення в апараті.
Ваше завдання — тримати програмний шлях легким і уникати серіалізації того, що має бути паралельним.

Якщо ви запускаєте mq-deadline на NVMe і бачите гіршу хвостову затримку або зниження пропускної здатності, це не дивно; це програмне забезпечення намагається перехитрити пристрій,
спроектований спеціально, щоб цього уникати.

Віртуалізовані або SAN-бекендові блочні пристрої

Тут слід припинити довіряти ярликам. «Диск» може бути віртуальним блочним пристроєм, який підкріплений мережею, RAID-контролером або масивом з власним кешуванням і чергуванням. У цих випадках:

  • Якщо пристрій здається ротаційним, але фактично підкріплений флеш-пам’яттю, ваш вибір може відрізнятися.
  • Якщо гіпервізор або масив уже робить сильне планування, «none» може бути кращим.
  • Якщо вам потрібна справедливість між кількома гостями, планувальник, що формує затримки, може допомогти — але перевіряйте.

Для багатьох віртуальних дисків mq-deadline все ще залишається безпечним дефолтом, якщо тільки постачальник явно не радить «none» і ви це довели.

Цікаві факти та історичний контекст (щоб зрозуміти дефолти)

  1. Оригінальний планувальник “deadline” був створений щоб запобігати голодуванню — реальна проблема, коли writeback міг поховати читання на повільних дисках.
  2. CFQ колись був дефолтом на багатьох дистрибутивах, тому що покращував інтерактивність десктопа, а не тому, що він максимізував серверну пропускну здатність.
  3. blk-mq з’явився щоб масштабувати IO на багатоядерних системах; старий одночерговий шлях став вузьким місцем при високих IOPS.
  4. “noop” історично радили для RAID-контролерів, бо контролер робив власне планування; «none» — це еквівалент ери blk-mq.
  5. NVMe спроектовано навколо множинних submission і completion черг, явно щоб зменшити contention і підвищити паралелізм.
  6. Інтент-лог ZFS (ZIL) існує через POSIX sync-симантику; це не функція продуктивності, а функція коректності з наслідками для продуктивності.
  7. ZFS на Linux (OpenZFS) дозрів пізніше ніж Solaris ZFS; взаємодії, специфічні для Linux (як-от blk-mq планувальники), стали темою тюнінгу лише після цього порту.
  8. “IOPS” стали масовою метрикою з появою флешу; в еру HDD ми в основному говорили про пропускну здатність, бо затримки були однаково жахливі.
  9. Сучасні ядра неодноразово змінювали дефолти; якщо ви копіюєте поради з 2016 року, ви, ймовірно, обираєте для ядра, якого вже немає.

Швидкий план діагностики: знайти вузьке місце без здогадок

Вас покликали. Затримки піднялися. Пул ZFS «виглядає нормально», бо він не кричить; він тихо псує вам день. Ось найкоротший шлях до істини.

Перше: ідентифікуйте клас пристрою і поточний планувальник

  • Це HDD, SATA SSD чи NVMe?
  • Чи дійсно планувальник той, що ви думаєте?
  • Чи ви тестуєте пул чи випадково лише один член vdev?

Друге: визначте, чи обмежує вас затримка або пропускна здатність

  • Перевірте per-device await, svctm еквіваленти (обережно) і глибину черги.
  • Зверніть увагу на симптоми хвостової затримки: таймаути додатків, зупинки sync-записів, ривки NFS.

Третє: відділіть «ZFS флашить» від «диск повільний»

  • Перевірте TXG і поведінку брудних даних (опосередковано через ZFS статистики і патерни навантаження).
  • Перевірте, чи sync-записи винуваті (і чи маєте ви ефективний SLOG).

Четверте: перевірте звичайних саботажників

  • Один помираючий диск у vdev викликає повтори і таймаути.
  • SMR HDD, що прикидається звичайним диском.
  • Споживчий SSD без захисту від втрати живлення, що карається sync-симантикою.
  • Проблеми з управлінням живленням PCIe/NVMe або дивні прошивки.

П’яте: лише тоді змінюйте планувальник

Зміни планувальника — низькоризикові в порівнянні зі зміною recordsize на завантаженому dataset, але вони також мають менший ефект у порівнянні з
виправленням дизайну sync-записів або заміною поганого диска. Змінюйте планувальник тоді, коли можете чітко описати режим відмови, який це вирішує:
голодування і справедливість (mq-deadline) vs зменшення накладних витрат і кращий паралелізм (none).

Практичні завдання (команди, приклади виводу та рішення)

Це реальні завдання, які ви можете виконати на хості Linux з ZFS. Кожне містить: команду, приклад того, що ви можете побачити, що це означає, і
рішення, яке приймаєте. Виконуйте їх у цьому порядку, коли діагностуєте систему, яку ви не збирали самі.

Завдання 1: перелічити блочні пристрої і помітити NVMe vs SATA

cr0x@server:~$ lsblk -d -o NAME,ROTA,TRAN,MODEL,SIZE
NAME  ROTA TRAN MODEL                 SIZE
sda      1 sata ST12000NM0008-2JH101 10.9T
sdb      1 sata ST12000NM0008-2JH101 10.9T
sdc      0 sata Samsung SSD 870 EVO   931.5G
nvme0n1  0 nvme Samsung SSD 980 PRO  953.9G

Значення: ROTA=1 — ротаційний (HDD). TRAN=nvme — NVMe. SATA SSD показують ROTA=0 і TRAN=sata.

Рішення: HDD — на mq-deadline. NVMe — на none. Для SATA SSD почніть з mq-deadline, якщо немає причин віддати перевагу none.

Завдання 2: перевірити поточний планувальник для кожного пристрою

cr0x@server:~$ for d in sda sdb sdc nvme0n1; do echo -n "$d: "; cat /sys/block/$d/queue/scheduler; done
sda: [mq-deadline] none
sdb: [mq-deadline] none
sdc: mq-deadline [none]
nvme0n1: [none]

Значення: Планувальник в дужках — активний. Тут SATA SSD (sdc) на none; HDD — на mq-deadline; NVMe — на none.

Рішення: Якщо SATA SSD — це SLOG або спеціальний vdev і ви бачите піки затримки, розгляньте переведення його на mq-deadline і поміряйте.

Завдання 3: перевірити, чи ядро взагалі пропонує очікувані планувальники

cr0x@server:~$ cat /sys/block/sda/queue/scheduler
[mq-deadline] none

Значення: На деяких системах ви можете бачити додаткові опції, як kyber або bfq. Якщо їх немає, ви не зможете їх вибрати.

Рішення: Не витрачайте час, ганяючись за планувальником з блог-посту, якщо ваше ядро його не підтримує. Дотримуйтесь mq-deadline/none і виправляйте справжні вузькі місця.

Завдання 4: підтвердити, які пристрої належать яким vdevs ZFS

cr0x@server:~$ zpool status -v tank
  pool: tank
 state: ONLINE
config:

        NAME                        STATE     READ WRITE CKSUM
        tank                        ONLINE       0     0     0
          mirror-0                  ONLINE       0     0     0
            ata-ST12000NM0008_1     ONLINE       0     0     0
            ata-ST12000NM0008_2     ONLINE       0     0     0
          mirror-1                  ONLINE       0     0     0
            ata-ST12000NM0008_3     ONLINE       0     0     0
            ata-ST12000NM0008_4     ONLINE       0     0     0
        logs
          nvme-Samsung_SSD_980PRO   ONLINE       0     0     0

Значення: ZFS будується з vdev. Продуктивність і режими відмов часто залежать від одного повільного або нездорового члена.

Рішення: Впроваджуйте зміни планувальника до реальних блочних пристроїв, що відповідають за члени vdev — особливо для logs і special vdevs.

Завдання 5: спостерігати за затримками та пропускною здатністю на рівні ZFS під навантаженням

cr0x@server:~$ zpool iostat -v tank 1
              capacity     operations     bandwidth
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
tank        5.12T  16.7T    180    620  21.3M  78.4M
  mirror-0  2.55T  8.35T     90    310  10.6M  39.2M
  mirror-1  2.57T  8.33T     90    310  10.7M  39.2M
logs            -      -      0    250     0  12.1M

Значення: Ви бачите, чи log-пристрій інтенсивно використовується (sync-навантеження) і чи операції читання/запису збалансовані між дзеркалами.

Рішення: Якщо log зайнятий і затримки погані, зміни планувальника на log-пристрої можуть вплинути на хвостову затримку — особливо якщо це SATA SSD.

Завдання 6: виявити затримки і насичення по пристрою (iostat)

cr0x@server:~$ iostat -x -d 1
Device            r/s     w/s   r_await   w_await   aqu-sz  %util
sda              2.1    78.3     18.2    145.7     9.84   99.0
sdb              1.9    77.5     17.9    141.2     9.53   98.7
nvme0n1          0.0   250.2      0.2      1.8     0.45   12.3

Значення: HDD насичені (%util ~99) з великим w_await. NVMe log виглядає добре. Вузьке місце — HDD vdevs, а не планувальник на NVMe.

Рішення: Якщо читання таймаутять, mq-deadline для HDD підходить; якщо він уже встановлений, наступний крок — формування навантаження (sync, recordsize, макет vdev) або додати шпінделі.

Завдання 7: підтвердити прапор rotational (він іноді брешe)

cr0x@server:~$ cat /sys/block/sdc/queue/rotational
0

Значення: 0 означає non-rotational. Для деяких RAID-контролерів або віртуальних пристроїв це може бути оманливим.

Рішення: Якщо «віртуальний диск» фактично підкріплений HDD і каже rotational=0, не встановлюйте none бездумно. Валідуйте за поведінкою затримок і вимогами постачальника.

Завдання 8: перевірити глибину черги пристрою і чи випадково ви не обмежуєте NVMe

cr0x@server:~$ cat /sys/block/nvme0n1/queue/nr_requests
1023

Значення: Це розмір черги запитів. Надто низьке значення може обмежувати пропускну здатність; надто високе — підвищувати затримки під деякими навантаженнями.

Рішення: Не чіпайте це, якщо немає виміряної проблеми з чергуванням. Вибір планувальника зазвичай достатній; більші регулювання мають більші побічні ефекти.

Завдання 9: тимчасово змінити планувальник (runtime) для пристрою

cr0x@server:~$ echo mq-deadline | sudo tee /sys/block/sdc/queue/scheduler
mq-deadline

Значення: Це змінює планувальник до перезавантаження (або поки udev не перевизначить його).

Рішення: Використовуйте це для контрольованих тестів у maintenance-вікні. Вимірюйте до/після за допомогою iostat і затримок додатку, а не на враженнях.

Завдання 10: підтвердити, що зміна застосована

cr0x@server:~$ cat /sys/block/sdc/queue/scheduler
[mq-deadline] none

Значення: Тепер він активний.

Рішення: Якщо продуктивність поліпшилась, але після перезавантаження повертається, потрібна персистентність (наступне завдання).

Завдання 11: зробити зміну персистентною через udev rule

cr0x@server:~$ sudo bash -c 'cat > /etc/udev/rules.d/60-io-scheduler.rules <
cr0x@server:~$ sudo udevadm control --reload-rules
cr0x@server:~$ sudo udevadm trigger --type=devices --action=change

Значення: Це застосовує політику планувальника на основі типу пристрою. Це не елегантно, але працює.

Рішення: Якщо ви керуєте флотом, внесіть це у конфігураційний менеджмент і ставтеся до цього як до будь-якого іншого базового налаштування: перевірено, протестовано і поступово розгорнуто.

Завдання 12: перевірити, що udev застосував правило після тригера

cr0x@server:~$ cat /sys/block/sda/queue/scheduler
[mq-deadline] none
cr0x@server:~$ cat /sys/block/nvme0n1/queue/scheduler
[none]

Значення: Добре: HDD — mq-deadline, NVMe — none.

Рішення: Переходьте до валідації навантаження. Політика планувальника — засіб, а не мета.

Завдання 13: виявити sync-важке навантаження (швидкий індикатор)

cr0x@server:~$ zfs get -o name,property,value -H sync tank
tank	sync	standard

Значення: sync=standard поважає поведінку синхронних викликів додатка. Якщо ваш додаток часто використовує fsync, пристрій журналу має значення.

Рішення: Не встановлюйте sync=disabled як «фікс продуктивності», якщо ви не готові втратити дані. Є кар’єри, що закінчуються таким чином.

Завдання 14: виміряти реальні затримки з fio проти ZVOL або dataset (обережно)

cr0x@server:~$ sudo fio --name=randread --filename=/tank/testfile --size=4G --rw=randread --bs=4k --iodepth=32 --numjobs=4 --direct=1 --time_based --runtime=30
randread: (groupid=0, jobs=4): err= 0: pid=22110: Fri Dec 25 02:10:11 2025
  read: IOPS=58.2k, BW=227MiB/s (238MB/s)(6815MiB/30002msec)
    clat (usec): min=90, max=9210, avg=265.4, stdev=112.7
     lat (usec): min=92, max=9220, avg=267.2, stdev=112.9

Значення: Ви отримуєте розподіл затримок, а не тільки пропускну здатність. Максимальна затримка показує поведінку хвостів.

Рішення: Якщо перехід з mq-deadline на none змінює середню, але погіршує максимальну затримку (або навпаки), вирішуйте, виходячи з чутливості додатку. Бази даних більше ненавидять хвостову затримку, ніж втрату 5% пропускної здатності.

Жарт №1: Якщо ви змінюєте IO-планувальники без вимірювання затримок, ви не налаштовуєте — ви займаєтесь астрологією зберігання.

Три корпоративні міні-історії з реального життя

Міні-історія 1: Інцидент через неправильне припущення (NVMe «потребує» mq-deadline)

Середня компанія працювала віртуалізаційний кластер на OpenZFS. Вони оновили обладнання, поставили нові NVMe диски
і зберегли старі playbook-налаштування. Цей playbook казав: «deadline зменшує затримку», тож вони встановили mq-deadline скрізь.

Зміна виглядала безпечньою. Перший тиждень був тихим. Потім вранці понеділка прийшла буря: завантаження VM, інгест бекапів і відмова БД.
Раптом вони побачили дивну поведінку: пропускна здатність виглядала нормальною, але 99-й перцентиль затримки різко підскочив і почав викликати таймаути додатків.
Гости не «повільніли». Вони зависали. Це різниця, що має значення.

Команда спочатку лазила по ZFS-налаштуваннях. Пробували міняти recordsize на кількох датасетах, сперечалися про знос SLOG, потім звинувачували гіпервізор.
Поки справжня підказка ховалася на виду: CPU у softirq і в блок-шляху піднявся, і затримки у завершенні IO стали більш варіабельні під конкуренцією.

Вони переключили NVMe на none на двох канарках і повторили те саме змішане навантаження. Хвостова затримка покращилася; накладні витрати CPU впали; зупинки зникли.
Старе припущення — «deadline завжди зменшує затримку» — було вірним у епоху HDD і інколи для SATA SSD. Для NVMe це виявився податок без вигоди.

Урок був не в тому, що «mq-deadline поганий». Урок — «підбирайте політику під пристрій». NVMe хоче паралелізму, а не нянькування.

Міні-історія 2: Оптимізація, що повернулася бумерангом (встановили none на HDD, щоб «дати ZFS робити свою справу»)

Інша організація вела великий бекап-репозиторій на ZFS з великими RAIDZ vdevs на HDD. Вони читали, що ZFS вже агрегує записи,
і вирішили, що планувальник зайвий. Хтось встановив усі диски на none, закомітив udev-правило і перейшов до наступного завдання.

Стала продуктивність під час нічного інгесту трохи покращилась. Люди похвалилися, що завжди буває перед тим, як система планує помсту. Наступне вікно scrub було першим реальним тестом: читання scrub плюс записи плюс кілька відновлень.

Завдання відновлення (читання) стали болісно повільними. Не «трохи повільнішими», а «користувачі думають, що відновлення зависло». Затримки під час записів різко підскочили.
Пул не падав; він просто витрачав вражаючий час, вирішуючи, коли виконати читання.

Корінь проблеми класичний: HDD під змішаним навантаженням можуть голодувати читання за записами, якщо не забезпечити певну справедливість.
Внутрішнє планування IO ZFS не завжди може компенсувати, коли порядок відправлення на блочному шарі фактично «будь-який прийшов — будь-який пішов».

Повернення HDD на mq-deadline відновило передбачувану поведінку читань під scrub та змішаними IO. Пропускна здатність під час інгесту трохи впала,
але відновлення стало надійним. Бізнес не платив за «найкращу пропускну здатність о 2 ранку» — вони платили за відновлення, що встигає до зустрічі.

Міні-історія 3: Нудна, але правильна практика, що врятувала ситуацію (бенчмарки по пристрою + канарки)

Фінансова компанія мала звичку: кожне оновлення ядра проходило через storage-канарки. Нічого вишуканого. Два хости на кожне покоління обладнання,
однаковий робочий набір, однакові дашборди. Вони тримали маленький базовий документ: типи пристроїв, версії прошивок, налаштування планувальника і очікувані діапазони затримок.

Одного кварталу рутинне оновлення ядра змінило поведінку на частині SATA SSD, що використовувалися як special vdevs. Нічого катастрофічного — просто повільне зростання хвостової затримки.
Канарки це зловили, бо дивилися на 99-й перцентиль, а не тільки на середню пропускну здатність. Вони також помітили, що пристрої більше часу витрачають на внутрішні обслуговування під змішаними записами.

Виправлення не було героїчним. Вони стандартизували ці SATA SSD на mq-deadline, переконались, що udev-правила застосовані послідовно,
і розгорнули це поступово, спостерігаючи за затримками. Це не було захопливо. Це було правильно.

Потім, коли сталася справжня подія — оновлення прошивки одного SSD спричинило короткі заминки — команда мала дисципліну тестувати зміни на канарках перш ніж масштабувати.
Базова політика планувальника допомогла їм не дебажити десять змін одночасно.

Нудні практики не отримують похвали до того, як вони запобігають дуже дорогоцінному виду хвилювань.

Жарт №2: IO-планувальник як офісна політика — ігноруєш його і все одно будеш страждати, але надмірна участь теж може зіпсувати тиждень.

Поширені помилки: симптом → корінь → виправлення

1) «NVMe швидкий, але мій пул ZFS зависає під навантаженням»

Симптом: Хороша середня пропускна здатність, але періодичні обриви затримки; CPU в ядрі зростає; таймаути додатків.

Корінь: NVMe працює з планувальником, що додає накладні витрати або зменшує конкурентність (часто mq-deadline), у поєднанні з глибоким чергуванням під змішаними IO.

Виправлення: Встановіть NVMe на none, перевірте хвостові затримки (fio + метрики додатку) і переконайтесь, що ви не обмежили глибину черги десь ще.

2) «Пропускна здатність HDD пула ок, але читання непридатні під бекапами чи scrub-ами»

Симптом: Роботи відновлення/читання повзають під час інтенсивних записів; інтерактивні читання зависають.

Корінь: HDD на none (або надмірно допустиме відправлення), що дозволяє сплескам записів голодувати читання.

Виправлення: Використовуйте mq-deadline на членах HDD vdev. Якщо це не допомагає — розділіть навантаження, додайте шпінделів або змініть макет vdev.

3) «Перехід на none покращив бенчмарки, але в продакшні стало гірше»

Симптом: fio показує більше IOPS, але реальні навантаження мають гіршу p99 затримку або більше джиттера.

Корінь: Бенчмарки вимірювали орієнтоване на пропускну здатність навантаження; продакшен чутливий до хвостової затримки і змішаних IO.

Виправлення: Бенчмаркуйте те, що справді запускаєте. Відстежуйте перцентилі затримок. Обирайте планувальник за p95/p99, а не за скрінами пікових IOPS.

4) «Налаштування планувальника не зберігаються після перезавантаження»

Симптом: Ехо в sysfs працює, але після перезавантаження все скидається.

Корінь: Зміни в sysfs діють лише під час роботи; udev або дефолти дистрибутива переписують їх при старті.

Виправлення: Використовуйте udev-правило (як показано) або механізм тюнінгу, що підтримує дистрибутив; перевірте після завантаження.

5) «Один диск повільний і отруює весь vdev»

Симптом: Продуктивність mirror/RAIDZ руйнується; iostat показує один пристрій з величезним await і помилками/повторами.

Корінь: Пошкоджений диск, поганий кабель, проблема контролера або прошивки; планувальник не виправить апаратні повтори.

Виправлення: Підтвердіть через SMART/NVMe логи; замініть апарат. Тримайте планувальник адекватним, але не вважайте його інструментом ремонту.

6) «Ми «виправили» latency sync, вимкнувши sync, і тепер ми сміливі»

Симптом: Затримки різко покращилися; потім втрата живлення і складно пояснити відсутні дані.

Корінь: Правильність обміняна на швидкість; ZFS робив все правильно раніше.

Виправлення: Використовуйте правильний SLOG з захистом від втрати живлення для sync-важких навантажень; тримайте sync=standard, якщо ви не готові навмисно втратити дані.

Чек-листи / покроковий план (пристосовано до change control)

Чек-лист A: вибір планувальника по пристрою

  1. Інвентаризація пристроїв: lsblk -d -o NAME,ROTA,TRAN,MODEL,SIZE.
  2. Сопоставлення пристроїв з vdev: zpool status -v.
  3. Встановіть базу:
    • HDD: mq-deadline
    • SATA/SAS SSD: mq-deadline (почніть звідси)
    • NVMe: none
  4. Якщо потрібно відхилитися — зафіксуйте, яку метрику ви оптимізуєте (p99 затримку, пропускну здатність, справедливість).

Чек-лист B: безпечне застосування змін

  1. Виберіть канарку (або лише одного члена vdev, якщо ризик низький і є резервність).
  2. Зафіксуйте базові метрики: zpool iostat -v 1, iostat -x 1, p95/p99 затримки додатку.
  3. Змініть планувальник в runtime через sysfs.
  4. Запустіть реальне робоче навантаження (не тільки синтетичний тест).
  5. Порівняйте хвостову затримку і накладні витрати CPU.
  6. Тільки після цього створіть персистентні udev-правила і розгорніть поступово.

Чек-лист C: валідація, що поведінка ZFS не погіршилась

  1. Scrub/resilver: чи не голодують вони продуктивні читання?
  2. Sync-запис: чи покращилось або погіршилось, і чи SLOG здоровий?
  3. Кількість помилок і повторів: чи не став якийсь диск «повільним» після зміни — швидше за все він просто зламався.

FAQ

1) Чи завжди варто використовувати mq-deadline з ZFS?

Ні. Використовуйте mq-deadline для HDD і зазвичай для SATA/SAS SSD. Для NVMe — none, якщо немає виміряної причини інакше.
ZFS виграє від передбачуваної затримки на повільних носіях; NVMe — від мінімального програмного втручання.

2) Чому «none» іноді дає кращі бенчмарки?

Бо він усуває накладні витрати планувальника і зберігає паралелізм. Особливо на NVMe «none» тримає програмний шлях легким,
дозволяючи контролеру робити те, для чого він спроектований.

3) Якщо ZFS уже планує IO, навіщо блоковий планувальник взагалі?

Не завжди «потрібен». Але для HDD планувальник корисний через справедливість і запобігання голодуванню.
ZFS не може повністю компенсувати механічні реалії обертового носія, коли порядок відправлення на блочному шарі непридатний.

4) А kyber?

kyber може бути корисним для контролю затримок на деяких пристроях. Якщо він доступний у вашому ядрі і у вас є конкретна проблема з затримками, яку mq-deadline не вирішує, варто протестувати.
Не розгортайте його по флоту лише тому, що на форумі був красивий графік.

5) А BFQ?

BFQ часто відмінний для інтерактивної справедливості, особливо на десктопах. На серверах з ZFS він рідше є правильним вибором, бо може додавати накладні витрати,
а цілі справедливості можуть не збігатися з вашою робочою задачею. Тестуйте, якщо вам потрібна справедливість по cgroup і ви можете дозволити собі ці витрати.

6) Чи впливає вибір планувальника на scrub і resilver ZFS?

Опосередковано — так. Scrub/resilver генерують тривалі читання і операції з метаданими. На HDD mq-deadline може не дозволити цим операціям бути похованими за записами (або навпаки),
підвищуючи передбачуваність. На NVMe none зазвичай тримає конвеєр ефективним.

7) Мій SSD SATA але відчувається «як NVMe». Чи все одно використовувати mq-deadline?

Почніть з mq-deadline. SATA все одно обмежений іншим командним моделем і часто простішим чергуванням пристрою. Деякі корпоративні SATA SSD нормально працюють з none,
але mq-deadline — безпечніша база під змішані навантаження.

8) Чи можна встановити один планувальник для всього пулу?

Ви встановлюєте планувальники по блочному пристрою, а не по пулу. Пул може містити HDD vdevs і NVMe SLOG; вони повинні мати різні планувальники.
Ставте лог/спеціальні пристрої на рівні першокласних — вони можуть домінувати над сприйманою затримкою.

9) Чому зміни повертаються, навіть з udev-правилами?

Бо щось інше теж їх встановлює (initramfs-скрипти, інструменти дистрибутива для тюнінгу або конфліктуюче udev-правило). Перевірте порядок правил
і діагностику через udevadm test при потребі. Виправлення — стандартизувати один механізм і прибрати конкурентний.

10) Яка найпростіша безпечна база для змішаних флотів?

HDD: mq-deadline. SATA/SAS SSD: mq-deadline. NVMe: none. Потім валідуйте на канарках для кожного покоління обладнання.
Це дає ~90% вигоди з мінімальним ризиком.

Висновок: наступні кроки, які варто зробити

Якщо ви запускаєте ZFS на Linux, рішення щодо IO-планувальника не романтичне:
mq-deadline для HDD і більшості SATA/SAS SSD, none для NVMe. Все інше — спеціальний випадок, що потребує доказів.

Наступні кроки, що приносять користь:

  1. Інвентаризуйте пристрої і підтвердьте поточні планувальники через sysfs.
  2. Сопоставте пристрої з ролями vdev в ZFS (data vs log vs special).
  3. Застосуйте базову політику планувальника і зробіть її персистентною через udev-правила.
  4. Виміряйте хвостові затримки до/після за допомогою iostat, zpool iostat і p95/p99 вашого додатку.
  5. Якщо затримки все ще погані, припиніть звинувачувати планувальник і досліджуйте дизайн sync-записів, несправне обладнання та макет vdev.

IO-планувальник — не магія. Це регулювальник руху. Встановіть його там, де він допомагає, приберіть там, де він заважає, і збережіть бюджет інцидентів для проблем, які того варті.

← Попередня
ZFS zfs list -o space: Подання, яке пояснює «Куди воно поділося?»
Наступна →
PostgreSQL проти CockroachDB: висока доступність без драми — або з новими видами болю

Залишити коментар