Глибина черги ZFS: чому деякі SSD літають на ext4 і задухають на ZFS

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

Ви переводите сервер з ext4 на ZFS, бо хочете контрольні суми, снапшоти, send/receive і приємне відчуття, що сховище більше не тримається на надії.
А потім з’являються графіки. Латентність підскакує, пропускна здатність вирівнюється, і SSD, що здавався ракетою на ext4, раптово поводиться так, ніби чекає на погодження від менеджменту.

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

Що насправді означає глибина черги (і чому це важливо)

Глибина черги — це скільки операцій вводу/виводу одночасно «в польоті» до пристрою. Якщо у вас лише один незавершений запит одночасно,
ви фактично їдете спортивною машиною на першій передачі, суворо дотримуючись обмеження 10 миль на годину.

SSD, особливо NVMe, спроектовані для паралелізму. Вони приховують внутрішню роботу (переклад адрес FTL, збір сміття,
вирівнювання носія) за допомогою множини незавершених команд. При низькій глибині черги ви отримуєте пристойну латентність, але посередню пропускну здатність. При вищій глибині черги зазвичай росте пропускна здатність…
до моменту, поки не настане обрив і латентність не вибухне.

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

Також «глибина черги» має два загальноприйняті значення:

  • Глибина черги на стороні хоста: скільки запитів ОС відправила, але пристрій ще не завершив.
  • Глибина черги на стороні пристрою: скільки команд знаходяться в чергах пристрою (NVMe має кілька submission/completion черг).

Якщо ви коли-небудь бачили, що SSD поводиться чудово при QD=1 і жахливо при QD=32, вітаю: ви зустріли різницю між «швидко» та «стабільно».

Чому ext4 може виглядати швидшим на тому ж SSD

Звичайний режим роботи ext4: прийняти записи, дозволити ядру page cache їх поглинути і відправити пізніше через writeback.
Для багатьох навантажень це означає, що застосунок відчуває швидкість, бо в основному пише в оперативну пам’ять. Коли приходить flush,
блочний шар ядра і планувальник можуть з’єднати, перемістити та стримувати I/O в стилях, які подобаються вашому SSD.

ZFS теж кешує, але за іншими правилами. ZFS — copy-on-write і транзакційна. Воно накопичує зміни в пам’яті,
потім фіксує їх у транзакційних групах (TXG). Також ZFS перевіряє дані за контрольними сумами, записує нові блоки замість перезапису старих
та підтримує метадані, які ext4 не мусить відстежувати так само.

Це може бути виграш у продуктивності або пастка — залежно від навантаження та пристрою:

  • Виграш: ZFS може агрегувати дрібні випадкові записи у більші, майже послідовні записи під час коміту TXG, що SSD часто сприймають добре.
  • Пастка: ZFS може створювати сплески: велика кількість I/O потрапляє на пристрій одночасно, глибина черги різко зростає і деякі SSD «розвалюються».
  • Пастка: I/O метаданих ZFS може бути інтенсивнішим (особливо при снапшотах, малих блоках і високій зміні даних).
  • Пастка: синхронні записи (fsync, O_DSYNC, бази даних) можуть бути жорстоко чесними. ext4 часто «виходить сухим» завдяки режиму ordered + бар’єрам,
    у той час як ZFS наполягає на коректності. Коректно може виглядати повільно, якщо ваше обладнання не підготовлене.

Практичний висновок: ext4 часто «виглядає швидшим» у тестах, які вимірюють час підтвердження операції, а не час запису на носій,
або випадково тестують page cache. ZFS має властивість відкривати реальну вартість надійності, особливо для синхронно-важких застосунків.

Як ZFS формує I/O: агрегація, txg і розрив реальності

The TXG rhythm: smooth on paper, spiky in production

ZFS збирає «брудні» дані в пам’яті і періодично фіксує їх як TXG. Цей коміт — момент, коли ZFS записує багато речей:
нові блоки даних, блоки метаданих, оновлені проміжні блоки, spacemaps і нарешті uberblocks.
Якщо система завантажена, можна отримати майже безперервний конвеєр TXG, але кожен з них все одно має момент «push».

Сплески самі по собі не погані. SSD люблять паралелізм. Проблема виникає, коли сплеск штовхає пристрій у його найгірший режим поведінки:
збір сміття, виснаження SLC-кешу, накладні витрати керування чергами прошивки або термальне троттлінгування.
ZFS не створив ці слабкості; воно просто виявило їх швидше, ніж ext4.

ZIO pipeline and concurrency knobs

ZFS не відправляє I/O як один потік. У нього є конвеєр (ZIO) зі стадіями: контрольні суми, стиснення, gang blocks, алокація,
відправка I/O, завершення тощо. У ZFS також є внутрішні обмеження конкурентності на vdev і для різних класів I/O.
Ці обмеження змінювалися між версіями OpenZFS і ОС, але ідея лишається: ZFS намагається бути справедливим і стабільним,
а не «максимальною глибиною черги за будь-яку ціну».

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

Why zvols can behave differently than datasets

ZFS dataset — це файлова система з recordsize (за замовчуванням часто 128K). Zvol — це блочний пристрій з volblocksize (часто 8K за замовчуванням).
Моделі I/O різні, метадані різні, і різний ступінь write amplification. З zvol ви легко можете отримати багато малих синхронних записів — особливо з образами VM і базами даних, які люблять fsync.

ext4 на raw-блочному пристрої може отримувати пристойний writeback і перемішування. Zvol може бути більш «літеральним», і ви за це платите.
Це не моральний недолік. Це інженерний вибір, який потрібно синхронізувати з робочим навантаженням.

Одна перефразована ідея, яку часто цитують у практиці:
перефразована ідея: «Надія — це не стратегія.» — часто приписується в SRE-кругах інженерам на кшталт Gene Kranz у дусі, але тут приведена цілком перефразовано.
(І так, вимірюйте, а не сподівайтеся.)

Де SSD задухають: обриви латентності, обмеження прошивки та змішане I/O

The latency cliff is real

Багато споживчих і prosumer SSD оптимізовані під десктопні сплески, низьку глибину черги і змішання з перевагою читань.
Вони блищать у синтетичних тестах ext4, які не утримують навантаження довго, щоб активувати «погані» режими.
Під час TXG-комітів ZFS або тривалих синхронних записів пристрій досягає стабільного стану, SLC-кеш спорожнюється,
і раптом ваш «3 GB/s» SSD робить «будь ласка почекайте» на 40–200 MB/s із латентністю, яка лякає застосунок.

Firmware fairness vs. throughput tricks

Enterprise-SSD часто жертвують піковими бенчмарк-числами заради передбачуваної хвостової латентності при високих глибинах черги.
Вони нудні. Нудне — це добре. Споживчі SSD часто ганяються за чудовими маркетинговими числами, спираючись на кеші та агресивне комбінування записів.
Це може бути чудово, поки навантаження не стане безперервним та багатопотоковим. Навантаження ZFS часто саме таке: безперервне і багатопотокове.

Mixed reads and writes with metadata

Метадані ZFS не безкоштовні. Снапшоти й клонування можуть примножувати роботу з метаданими. Дрібні випадкові записи створюють більше метаданих.
Якщо ваш пул майже заповнений, виділення простору ускладнюється, і spacemap активніший. SSD бачить мікс:
дрібні читання для метаданих, записи для даних і синхронні точки для консистентності.
Деякі диски впораються з цим граціозно. Деякі — як дитина з віолончеллю.

Жарт №1: Я одного разу запитав споживчий SSD про його стабільну швидкість запису. Він відповів термальним троттлінгом з образи.

Alignment and ashift: the silent performance tax

Якщо ashift пулу не відповідає реальному фізичному розміру секторів пристрою, ви можете змусити поведінку read-modify-write.
Це означає, що кожен «дрібний» запис може перетворитися на кілька внутрішніх операцій. ext4 теж страждає від невирівнювання,
але ZFS робить легше створити постійну неправильну конфігурацію під час створення пулу.

Sync write semantics: ZFS refuses to lie

Найшвидший спосіб зробити ZFS «повільним» — запускати синхронно-важке навантаження на пристроях без захисту від втрати живлення і без належного SLOG,
при цьому очікуючи поведінку, як у ext4. ZFS виконає запит: «зробіть це надійним».
Ваш SSD зробить найкращу імітацію обертального диска.

Цікавинки та історичний контекст

  • ZFS виник у Sun Microsystems у середині 2000-х, спроєктований для цілісності даних і об’єднаного зберігання, а не для гонитви за одиночними бенчмарк-трофеями.
  • Copy-on-write не винайшов ZFS, але ZFS популяризував його для загального використання в масштабі з інтегрованим управлінням томами.
  • NVMe представив множинні апаратні черги, щоб зменшити блокування та накладні витрати CPU у порівнянні з SATA/AHCI, роблячи глибину черги та прив’язку CPU більш помітними у продуктивності.
  • Ранні контролери SSD були сумно відомі обривами запису, коли їхні внутрішні таблиці відображення або кеші заповнювалися; сучасні диски кращі, але форма обриву досі існує.
  • ZFS давно використовує транзакційні групи для пакетування змін; це пакетування може покращити пропускну здатність, але також створює сплески, які виявляють слабкі диски.
  • Планувальники I/O в Linux еволюціювали від CFQ до deadline до mq-deadline і none; з NVMe багато стеків віддають перевагу «none», переміщуючи більше поведінки на пристрій і файлову систему.
  • Розміри секторів — це хаос: 512e і 4Kn існують через те, що індустрія намагалася перейти на 4K сектора, не зламавши все одразу.
  • Контрольні суми блоків даних означають, що читання ZFS часто перевіряються наскрізь; це невелика робота для CPU, але реальна, і вона змінює відчуття «швидко» під навантаженням.

Швидкий план діагностики

Коли ZFS «задухає», ви не починаєте з хаотичного перемикання випадкових налаштувань. Ви починаєте з визначення, яка черга заповнюється:
застосунок, ARC, ZIO, vdev, блочний шар ядра чи сам SSD. Ось швидка послідовність, яка працює, коли pager кричить.

First: identify whether you’re bound by latency, bandwidth, CPU, or sync

  1. Перевірте латентність і черги на пристрій (iostat). Якщо await і aqu-sz ростуть, пристрій насичений або поводиться неправильно.
  2. Перевірте час очікування на рівні ZFS (zpool iostat -w). Якщо ZFS показує високі часи очікування, вузьке місце під ZFS, а не в ARC.
  3. Перевірте CPU і softirqs. Якщо CPU завантажений у kernel або softirq, «проблема зі зберіганням» може бути контенцією CPU.
  4. Перевірте, чи навантаження синхронно-важке. Якщо так, трактуйте це як проблему надійності перш за все.

Second: isolate which kind of I/O is hurting

  1. Читання проти записів: чи повільні читання через метадані, що трясуться?
  2. Малі випадкові проти великих послідовних: чи mismatch recordsize/volblocksize?
  3. Стабільний стан проти сплесків: чи продуктивність падає через хвилину? Це SLC-кеш/GC/термальна поведінка.

Third: confirm pool layout and the non-negotiables

  1. Заповненість пулу: якщо ви вище ~80–90% на багатьох пулах, витрати на алокацію зростають і SSD страждають.
  2. ashift: неправильний ashift — назавжди, якщо не перебудувати.
  3. Стратегія sync: якщо вам потрібні синхронні семантики, використовуйте відповідне обладнання або прийміть витрати.

Практичні завдання: команди, виводи, рішення (12+)

Ось перевірки, які я виконую, коли хтось каже «ext4 був швидшим». Мета не в збиранні дрібниць.
Мета — вирішити, що виправити, що лишити і що перебудувати.

Task 1: Confirm the device and transport (NVMe vs SATA, link speed)

cr0x@server:~$ lsblk -d -o NAME,MODEL,TRAN,ROTA,SIZE
NAME MODEL            TRAN ROTA   SIZE
nvme0n1 SAMSUNG_MZVLW1 nvme    0 953.9G
sda   ST2000DM008     sata    1   1.8T

Що це означає: TRAN показує, чи ви на NVMe чи SATA; ROTA показує ротаційність.
Якщо ви очікували NVMe, а бачите SATA, ваша «проблема ZFS» може бути проблемою закупівлі.
Рішення: Перевірте ціль тестування. Не налаштовуйте ZFS під неправильний клас пристрою.

Task 2: Check kernel I/O scheduler for the device

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

Що це означає: NVMe часто працює з none, тобто мінімальне планування на хості.
Рішення: Якщо ви бачите bfq на швидкому NVMe і гонитесь за пропускною здатністю, розгляньте none або mq-deadline.
Якщо вам важлива стабільність латентності під змішаним навантаженням, mq-deadline може бути розумнішим за «довіритися прошивці».

Task 3: Observe queue depth and latency live (block layer view)

cr0x@server:~$ iostat -x 1 nvme0n1
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           8.21    0.00    4.88    2.44    0.00   84.47

Device            r/s     w/s   rKB/s   wKB/s  rrqm/s  wrqm/s  %util  await  aqu-sz
nvme0n1         1200    9000   98000  620000     0.0     0.0   99.5   6.80   62.4

Що це означає: aqu-sz — середній розмір черги; await — середня латентність.
%util близько 100% означає, що пристрій зайнятий.
Рішення: Якщо розмір черги величезний і латентність росте, ви насичуєте пристрій або вдаряєтеся в обрив прошивки.
Якщо черга мала, але пропускна здатність низька, вузьке місце вище пристрою (CPU, sync або обмеження ZFS).

Task 4: Check ZFS vdev latency and queueing

cr0x@server:~$ zpool iostat -v 1
               capacity     operations     bandwidth
pool         alloc   free   read  write   read  write
tank         1.23T  2.41T    900   7200  110M   690M
  mirror     1.23T  2.41T    900   7200  110M   690M
    nvme0n1      -      -    450   3600   55M   345M
    nvme1n1      -      -    450   3600   55M   345M

Що це означає: Це показує, чи ZFS відправляє I/O і як він розподілений по vdev.
Рішення: Якщо один leaf vdev повільніший, він потягне за собою весь пул. Замініть проблемний носій або перебалансуйте архітектуру.

Task 5: Confirm pool health and error counters

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

        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            nvme0n1 ONLINE       0     0     0
            nvme1n1 ONLINE       0     0     0

errors: No known data errors

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

Task 6: Check dataset properties that change I/O shape

cr0x@server:~$ zfs get -o name,property,value -s local,default recordsize,compression,atime,primarycache,sync tank/data
NAME       PROPERTY      VALUE
tank/data  recordsize    128K
tank/data  compression   zstd
tank/data  atime         off
tank/data  primarycache  all
tank/data  sync          standard

Що це означає: recordsize впливає на write amplification для дрібних випадкових записів; sync впливає на поведінку збереження.
Рішення: Для баз даних з 8K сторінками розгляньте recordsize=16K або 8K тільки якщо розумієте витрати на метадані.
Не копіюйте сліпо; вимірюйте.

Task 7: Check zvol settings if you’re serving VM disks or iSCSI

cr0x@server:~$ zfs get -o name,property,value -s local,default volblocksize,compression,sync,logbias tank/vm0
NAME      PROPERTY      VALUE
tank/vm0  volblocksize  8K
tank/vm0  compression   off
tank/vm0  sync          standard
tank/vm0  logbias       latency

Що це означає: Малий volblocksize може збільшити IOPS, але також покарати пул метаданими й фрагментацією.
Рішення: Якщо ви бачите багато синхронних записів і немає SLOG, очікуйте болю. Якщо SLOG є, logbias=latency — розумний вибір.

Task 8: Detect sync-heavy behavior from the application side

cr0x@server:~$ strace -f -tt -e trace=fdatasync,fsync,pwrite64 -p 2143
12:19:41.102334 fdatasync(7) = 0
12:19:41.104981 pwrite64(7, "...", 8192, 123904) = 8192
12:19:41.106204 fdatasync(7) = 0

Що це означає: Якщо ви бачите часті fsync/fdatasync, ваше навантаження піклується про стійкість і порядок.
Рішення: Трактуйте це як проблему латентності синхронних записів. Розгляньте SLOG (з PLP), зміну sync тільки з чітким розумінням ризиків.

Task 9: Verify SLOG presence and whether it’s actually being used

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

        NAME         STATE     READ WRITE CKSUM
        tank         ONLINE       0     0     0
          mirror-0   ONLINE       0     0     0
            nvme0n1  ONLINE       0     0     0
            nvme1n1  ONLINE       0     0     0
        logs
          nvme2n1    ONLINE       0     0     0

Що це означає: Пристрій під logs — це окремий intent log (SLOG).
Рішення: Якщо ви працюєте з синхронно-важкими навантаженнями, правильний SLOG може зменшити хвостову латентність. Якщо ваш SLOG — споживчий SSD без PLP,
ви купуєте швидкість за ризиком цілісності. Не робіть так.

Task 10: Check pool fragmentation and capacity pressure

cr0x@server:~$ zpool list -o name,size,alloc,free,cap,frag,health
NAME  SIZE  ALLOC   FREE  CAP  FRAG  HEALTH
tank  3.64T  3.20T   440G  87%   62%  ONLINE

Що це означає: Високі cap і frag часто корелюють з гіршою поведінкою алокації і більшою метаданою активністю.
Рішення: Якщо ви майже заповнені, перестаньте тюнити й почніть планувати додаткову ємність. Вільне місце — це продуктивність.

Task 11: Measure ZFS ARC behavior (are you actually caching?)

cr0x@server:~$ arcstat 1 3
    time  read  miss  miss%  dmis  dm%  pmis  pm%  mmis  mm%  arcsz     c
12:20:10  9850  1200     12   500   5    700   7      0   0   32.0G  32.0G
12:20:11 10310  1500     15   800   8    700   7      0   0   32.0G  32.0G
12:20:12  9980  2200     22  1600  16    600   6      0   0   32.0G  32.0G

Що це означає: Зростаючий miss% означає, що ви частіше звертаєтеся на диск.
Рішення: Якщо робочий набір не вміщується і у вас читально-важке навантаження, подумайте про більше RAM або реструктуризацію dataset-ів.
Не додавайте L2ARC як першу реакцію; він може додати накладних витрат.

Task 12: Check TRIM/discard status (SSD steady-state behavior)

cr0x@server:~$ zpool get autotrim tank
NAME  PROPERTY  VALUE     SOURCE
tank  autotrim  on        local

Що це означає: autotrim=on допомагає SSD підтримувати продуктивність, інформуючи про вільні блоки.
Рішення: Якщо autotrim вимкнено на SSD-пулах і у вас є велика зміна даних, розгляньте ввімкнення (після перевірки підтримки ОС/ZFS).

Task 13: Confirm ashift (alignment) on each vdev

cr0x@server:~$ zdb -C tank | grep -E 'ashift|path' -n
128:            path: '/dev/nvme0n1'
135:            ashift: 12
142:            path: '/dev/nvme1n1'
149:            ashift: 12

Що це означає: ashift: 12 відповідає 4K секторам. Багатьом SSD це потрібно.
Рішення: Якщо ви бачите ashift: 9 на сучасних SSD — ймовірно, у вас постійний штраф за продуктивність. Перебудуйте пул правильно.

Task 14: Check NVMe health indicators and throttling hints

cr0x@server:~$ nvme smart-log /dev/nvme0n1
Smart Log for NVME device:nvme0n1 namespace-id:ffffffff
critical_warning                    : 0x00
temperature                         : 71 C
available_spare                     : 100%
percentage_used                     : 3%
data_units_read                     : 123,456,789
data_units_written                  : 98,765,432
host_read_commands                  : 4,321,000,000
host_write_commands                 : 7,654,000,000
controller_busy_time                : 12,345
media_errors                        : 0
num_err_log_entries                 : 0

Що це означає: 71°C може торкатись зони троттлінгу для деяких дисків.
Рішення: Якщо продуктивність падає під навантаженням і температура висока — виправте потік повітря перед тим, як писати довідковий документ з налаштувань.

Task 15: Reproduce with a benchmark that controls queue depth and bypasses cache

cr0x@server:~$ fio --name=randwrite --filename=/tank/data/fio.test --size=8G --direct=1 --ioengine=libaio --rw=randwrite --bs=4k --iodepth=32 --numjobs=4 --group_reporting
randwrite: (groupid=0, jobs=4): err= 0: pid=8812: Fri Dec 22 12:24:33 2025
  write: IOPS=52.4k, BW=205MiB/s (215MB/s)(8192MiB/39945msec)
    slat (usec): min=4, max=980, avg=18.21, stdev=9.44
    clat (usec): min=50, max=120000, avg=2400.15, stdev=7800.22
    lat (usec): min=60, max=120500, avg=2419.10, stdev=7800.40

Що це означає: Середня латентність 2.4ms, але максимум 120ms: хвостова латентність страшна.
Рішення: Якщо ext4 виглядає «швидшим», повторіть той же профіль fio на ext4 з direct=1.
Якщо хвостова латентність ZFS гірша, зосередьтесь на sync, заповненості пулу, температурі/поведінці прошивки пристрою та невідповідності I/O шаблонів.

Типові помилки: симптом → причина → виправлення

1) “Throughput is fine, but latency spikes every few seconds”

Симптом: Періодичні стрибки латентності; таймаути застосунку; графіки виглядають як серцебиття.

Причина: Сплески комітів TXG, що потрапляють у слабкий режим стабільного запису SSD (виснаження SLC-кешу, GC) або термальний троттлінг.

Виправлення: Підтвердьте steady-state тести fio і NVMe температуру. Покращіть охолодження, обирайте SSD з передбачуваною стабільною швидкістю запису, тримайте пул під контролем заповнення.

2) “ext4 beats ZFS by 2–5× on writes in my test”

Симптом: Прості копіювання файлів або наївні бенчмарки показують, що ext4 значно швидше.

Причина: Бенчмарк вимірює page cache і відкладені записи, а не стійкість; тест ZFS потрапляє на синхронні семантики або прямий I/O.

Виправлення: Використовуйте direct=1 у fio або принаймні скидайте кеші; порівнюйте схоже з схожим (sync vs async, buffered vs direct).

3) “VM storage on zvol is slow, datasets look okay”

Симптом: Погані IOPS випадкових записів, зупинки при fsync, скарги від гостьових ОС.

Причина: Малий volblocksize + синхронно-важке навантаження гостьової ОС + відсутність SLOG; також можливе невідповідне співвідношення volblocksize до файлової системи гостя.

Виправлення: Додайте належний SLOG (PLP), розгляньте підбір volblocksize відповідно до навантаження, або зберігайте деякі VM на dataset-ах; перевірте очікування щодо sync.

4) “It got worse after we enabled compression”

Симптом: Більше завантаження CPU, менша пропускна здатність, більше латентності під навантаженням.

Причина: CPU став вузьким місцем, або алгоритм стиснення занадто важкий для доступного процесорного бюджету; також це може змінити розподіл розмірів I/O.

Виправлення: Використовуйте швидший алгоритм (наприклад, zstd на низькому рівні), усуньте CPU-конкуренцію, виміряйте знову. Стискання — це компроміс.

5) “Everything was fine until the pool hit 85–90%”

Симптом: Записи сповільнюються, читання метаданих зростають, фрагментація підвищується.

Причина: Алокація ускладнюється; SSD бачить більше випадкових записів; ZFS має менше великих суміжних областей.

Виправлення: Додайте ємність, видаліть/перенесіть дані, зменшіть churn снапшотів, тримайте запас місця. Налаштування не замінить вільний простір.

6) “We set sync=disabled and it’s fast now”

Симптом: Продуктивність різко покращилась; усі святкують.

Причина: Ви обміняли стійкість на швидкість. Після збою можна втратити підтверджені записи. На деяких системах це може пошкодити інваріанти на рівні застосунку.

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

Три корпоративні міні-історії

Mini-story 1: The incident caused by a wrong assumption

Середня SaaS-компанія перемістила навантажений кластер PostgreSQL з ext4 на RAID10 до ZFS mirror-ів на «швидких» NVMe.
План міграції був добрий: снапшоти, пункти відкату, контрольований cutover — звичні дорослі речі.
Єдина непроявлена припущення: «NVMe — значить NVMe, буде нормально».

Через кілька годин вони побачили періодичні затримки запитів. Не постійну повільність — гірше. Випадкові паузи 2–10 секунд, що виснажували connection pool.
Логи бази показували сплески повільних fsync. ОС виглядала спокійною. CPU в нормі. Мережа в нормі. Графіки зберігання виглядали як сейсмограф.

Причина не в накладних витратах ZFS на коректність. Це поведінка моделі SSD у стабільному стані під постійним синхронним тиском.
Під ext4 навантаження «вирівнювалося» page cache і кешем RAID-контролера (з батареєю). Під ZFS, з коректними синхронними семантиками і без виділеного лог-пристрою, пул змусив SSD показати справжню хвостову латентність.

Виправлення було не гламурним: додали правильні PLP-лог-пристрої, відкоригували макет пулу під навантаження і замінили найгіршу модель SSD на диски з передбачуваною стабільною латентністю запису.
Висновок постмортему був ще менш гламурний: у чек-листи закупівель додали тести на стабільний запис, а не лише IOPS зі специфікації.

Mini-story 2: The optimization that backfired

Внутрішня платформа керувала мультиорендним віртуалізаційним кластером. Команда гордилася знанням ZFS і хотіла максимум продуктивності.
Вони побачили пост в форумі з приблизно таким сенсом: «збільшіть конкурентність; ZFS консервативний».
Вони відрегулювали кілька параметрів модуля ZFS, щоб дозволити глибші черги і більше незавершених I/O на vdev.

У одноорендних бенчмарках все виглядало чудово. Пропускна здатність зросла. А потім повернулося реальне навантаження:
десятки VM з міксованими читаннями, записами і синхронними сплесками. Хвостова латентність стала гіршою. Значно гіршою.

Система стала відмінною в насиченні SSD і жахливою в підтримці передбачуваної латентності.
Під змішаним навантаженням глибші черги призводили до групування запитів. Прошивка SSD відповідала внутрішнім перемішуванням і довгими паузами GC.
Середні метрики виглядали добре. 99.9-й перцентиль — ні.

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

Mini-story 3: The boring but correct practice that saved the day

Фінансова компанія (тобто аудити і довга пам’ять) використовувала ZFS для пайплайна лог-інжесту.
Не гламурно. Переважно послідовні записи з періодичними компресіями. У них була політика: ніколи не тримати пули вище 75%,
завжди вмикати autotrim на SSD-пулах і тестувати нові моделі SSD на 30-хвилинних steady-state записах перед затвердженням.

Одного кварталу вендор підмінив модель SSD через дефіцит. На папері вона була швидша.
Команда все одно запустила steady-state тест. На 12-й хвилині латентність запису піднялася на порядок і там залишилася.
Диск не був дефектним; він просто робив те, що робить, коли його кеш і таблиці мапування під тривалим навантаженням.

Вони відхилили заміну і лишили старішу модель. Місяць потому інший відділ розгорнув підмінений диск в іншій системі
і витратив тижні на пошук періодичних таймаутів. Команда ZFS не мусила казати «казали ж» вголос.
Сумні, але коректні практики — запас місця, політика trim і steady-state тести — запобігли довготривалому інциденту.

Жарт №2: Найкращий тюнінг продуктивності іноді — це таблиця і вміння сказати «ні», тому він рідко впроваджується.

Чеклісти / покроковий план

Step-by-step: reproduce the ext4 vs ZFS claim without lying to yourself

  1. Виберіть той самий пристрій і стиль розмітки. Не порівнюйте ext4 на raw-диску з ZFS на sparse zvol, якщо ви цього не маєте на увазі.
  2. Спочатку робіть тест прямого I/O. Використовуйте fio з direct=1, щоб виміряти пристрій + файлову систему, а не RAM.
  3. Тестуйте на кількох глибинах черги. QD=1, 4, 16, 32. Дивіться, де ламається латентність. Ця точка перелому важливіша за пікові IOPS.
  4. Запускайте довго, щоб досягти steady state. Хвилини, не секунди. Багато SSD-обривів з’являються після виснаження кешів.
  5. Розділяйте синхронні та асинхронні тести. Якщо ваше навантаження робить fsync, тестуйте fsync. Якщо ні — не карбуйте себе синхронними тестами.

Step-by-step: production-safe tuning order (least regret first)

  1. Виправте апаратні/прошивкові реалії. Охолодження, правильний клас SSD, уникайте дешевих дисків для синхронно-важких робочих навантажень.
  2. Виправте макет і ємність пулу. Запас місця, дизайн vdev, mirror проти RAIDZ залежно від вимог по латентності.
  3. Виправте очевидні невідповідності dataset-ів. recordsize/volblocksize, atime, рівень стиснення.
  4. Вирішіть семантику sync правильно. SLOG з PLP або прийміть витрати на продуктивність.
  5. Лише потім чіпайте внутрішні налаштування ZFS. І робіть це з планами відкату та вимірюваними результатами.

Checklist: before you blame ZFS

  • Чи порівнюєте ви буферизовані записи в ext4 з durable-записами в ZFS?
  • Чи пул заповнений більше 80–85% або сильно фрагментований?
  • Чи висока температура SSD під навантаженням?
  • Чи навантаження часто виконує fsync/fdatasync?
  • Чи ashift правильний?
  • Чи використовуєте ви zvol там, де dataset був би простішим (або навпаки)?
  • Чи у вас передбачувані enterprise SSD або «пікові» споживчі диски?

FAQ

1) Is ZFS “lower queue depth” by design?

ZFS схильне управляти конкурентністю, щоб захистити латентність і справедливість. Воно може генерувати високу глибину черги під навантаженням, але намагається не «спалити» пристрій.
Якщо ваш SSD потребує екстремального QD для продуктивності — це характеристика пристрою, яку слід перевіряти в steady state.

2) Why do some SSDs benchmark great on ext4 and terrible on ZFS?

Бенчмарки ext4 часто потрапляють у page cache і відкладений writeback, маскуючи обриви пристрою. ZFS може створювати більш правдиві шаблони: сплески при TXG-коміті,
більше метаданих і явну sync-поведінку. Слабкі SSD у стабільному стані обнажуються.

3) Should I change the Linux I/O scheduler for NVMe when using ZFS?

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

4) Does adding a SLOG always improve performance?

Лише для синхронних записів. Для асинхронних навантажень SLOG дасть мало користі. Для синхронно-важких навантажень правильний SLOG з PLP може значно зменшити хвостову латентність.
Неправильний SLOG без PLP — це гра в надію на цілісність, а не оптимізація.

5) Are zvols inherently slower than datasets?

Не за визначенням, але вони поводяться інакше. zvol можуть підсилювати дрібні випадкові записи і синхронні шаблони. Datasets краще агрегують записи природно.
Обирайте залежно від навантаження: образи VM і iSCSI часто хочуть zvol; файлові навантаження — dataset.

6) What’s the single biggest “oops” that causes ZFS SSD pain?

Запуск синхронно-важкого навантаження на споживчих SSD без PLP і без справжнього SLOG, а потім очікування низької хвостової латентності.
На другому місці — робота пулів надто заповнених і здивування, чому алокація повільна.

7) Should I tune recordsize to 8K for databases?

Іноді, але це не безкоштовно. Менший recordsize може зменшити read amplification для дрібних читань, але збільшує метадані та ризик фрагментації.
Багато баз працюють добре з 16K або 32K; дехто потребує 8K. Вимірюйте з реалістичною конкурентністю та steady-state тестами.

8) How can I tell if I’m seeing an SSD SLC cache cliff?

Запустіть тривалий тест запису (10–30 хвилин) з прямим I/O і реалістичною глибиною черги.
Якщо пропускна здатність різко падає після короткого інтервалу і латентність зростає, це класичне виснаження кеша або поведінка GC.

9) Is autotrim safe to enable?

На сучасних OpenZFS і SSD autotrim зазвичай безпечний і допомагає стабільній продуктивності. Проте перевіряйте у вашому середовищі.
Якщо у вас стара прошивка або складні віртуалізаційні шари — протестуйте спочатку.

10) Why does performance change with snapshots?

Снапшоти збільшують роботу з метаданими і можуть підвищувати фрагментацію при churn. Видалення стає складнішим, бо блоки посилаються снапшотами.
Це може змінити поведінку запису і підвищити випадковий I/O, який деякі SSD погано витримують при зростанні глибини черги.

Висновок: наступні кроки, які можна зробити сьогодні

Якщо SSD «літає на ext4 і задухає на ZFS», ви, ймовірно, бачите одне з трьох: бенчмарк, що лестить ext4, тест кешу,
реаліті-чек синхронної латентності або SSD, який колабує під тривалим змішаним I/O при зростанні глибини черги.
ZFS рідко винуватий. Воно — аудитор.

Зробіть наступне:

  1. Повторно протестуйте з fio, використовуючи direct I/O на різних глибинах черги і довго, щоб досягти steady state.
  2. Захопіть iostat і zpool iostat під час спаду і визначте, чи вузьке місце — насичення пристрою, синхронна латентність чи CPU/interrupt-накладні.
  3. Перевірте запас місця в пулі і ashift; якщо ви занадто заповнені або невирівняні — виправляйте архітектуру, а не симптоми.
  4. Якщо проблема — sync, вирішуйте її правильно: PLP SLOG, кращі SSD або прийняття вартості за надійність.
  5. Опирайтеся на випадковий тюнінг. Тюньте тільки після того, як зможете пояснити, яка черга заповнюється і чому.

ZFS — це система для тих, хто віддає перевагу реальності над відчуттями. Якщо ви хочете «відчуття», купіть маркетинговий бенчмарк і повісьте його в рамці.

← Попередня
Debian 13: Journald з’їв ваш диск — обмежте логи, не втрачаючи важливого
Наступна →
Docker на cgroups v2: біль, помилки та шлях виправлення

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