Хтось підносить скріншот: «Наша нова ZFS-система робить 6 GB/s!» Ви ставите одне питання — «Звідки?» — і в кімнаті стає тихо. Бо найшвидший пристрій зберігання в дата-центрі — це той, який ви не збиралися тестувати: RAM. Другий за швидкістю — той, який ви забули, що ввімкнули: compression.
Бенчмарки — це те, як проєкти збереження даних отримують фінансування, погодження й потім звинувачення. У продакшені «майже правильно» означає те саме, що неправильно, але з приємнішими графіками. Це набір правил і польових методів для бенчмаркінгу ZFS без самообману — перед вашим шефом, командою чи тим, хто чергує наступним.
Що ви насправді вимірюєте (а що — ні)
Бенчмаркінг ZFS зазнає поразки через одну основну причину: люди тестують «зберігання», ніби це одна річ. Це не так. Ви бенчмаркуєте конвеєр: application → libc → kernel VFS → ZFS DMU → ZIO scheduler → vdev queues → disks/flash → controller → firmware. Додайте ARC, L2ARC, SLOG, compression, checksums і метадані — і ви тестуєте систему з більшим числом рухомих частин, ніж будь-яка корпоративна реорганізація.
Є три числа, які людей цікавлять:
- Пропускна здатність (MB/s або GB/s): швидкість масового читання/запису. Підходить для бекапів, медіа, послідовних сканів і красивих слайдів.
- IOPS: операції в секунду. Потрібне для дрібних блоків, випадкового доступу, метаданих і реальних баз даних.
- Затримка (особливо p95/p99): єдине число, яке відчувають ваші користувачі. ZFS може давати високу пропускну здатність, тихо вбиваючи хвостову затримку.
Бенчмарк, що дає одне число без розподілу затримки, — це швидше «перевірка настрою», ніж інженерія.
Бенчмаркінг — це висновування, а не пряме вимірювання
Зберігання важко «виміряти» прямо, бо система адаптується. ARC нагрівається. Transaction groups (TXGs) групують роботу. ZFS prefetch і readahead змінюють патерни. Compression змінює фізичні байти. Якщо ви не контролюєте ці змінні, ви не тестуєте пул — ви тестуєте те, що ZFS вирішив робити, поки ви дивилися.
Сухе правило: якщо ви не можете пояснити чому результат покращився, то він не покращився. Вам просто пощастило.
Кілька фактів і історія, що змінюють підхід до бенчмарку
Трохи контексту допомагає передбачити поведінку ZFS під час тестів. Ось конкретні факти, що важливі в лабораторії й у продакшені:
- ZFS розробляли з енд‑ту‑енд цілісністю даних як першопочатковою метою, а не як додаток. Checksums, copy-on-write і self-healing впливають на write amplification і затримку.
- Ранні роботи над ZFS у Sun мали на меті змусити звичайні диски поводитися «достатньо ентерпрайзно». Суть була в тому, щоб виживати при ненадійному залозі за допомогою розумного софту. Бенчмарки, що ігнорують опції цілісності, пропускають головне.
- ARC — не просто кеш, це політика управління пам’яттю. Він конкурує з вашим застосунком за RAM, а його поведінка змінюється з навантаженням. Бенчмаркінг без контролю ARC — це бенчмаркінг управління пам’яттю.
- Copy-on-write означає, що «перезапис» — це насправді allocate-new + update-metadata. Випадкові перезаписи поводяться як випадкові записи плюс метадані. Файлові системи, що перезаписують на місці, можуть виглядати «швидшими» на деяких патернах, допоки не почнуть псувати дані.
- TXG‑групування — от чому короткі тести брешуть. ZFS групує записи в TXG і комітить періодично. Якщо ви тестуєте 10 секунд, ви можете ніколи не побачити steady‑state поведінки.
- SLOG існує через те, що синхронні записи дорогі. ZIL є завжди; SLOG — це окремий пристрій, що може прискорити sync‑записи. Якщо ви ніколи не тестували sync‑поведінку, ви бенчмаркуєте неправильний ризик.
- Recordsize — це контракт продуктивності. ZFS вміє ефективно зберігати великі записи для послідовних навантажень, але великі recordsize можуть карати дрібні випадкові записи через read‑modify‑write патерни.
- Вирівнювання секторів (ashift) — назавжди. Обрано неправильно — і кожен запис може стати двома. Багато чого можна виправити в ZFS, але ви не зможете «натюнити» неправильний ashift без перебудови.
- Compression часто робить ZFS «швидшим», бо відбувається менше I/O. Це не шахрайство — якщо ваші дані стискаються в продакшені. Якщо ні — то це еквівалент змагальної підготовки з підхопленням із гори.
Один вислів, щоб зберегти чесність:
«Надія — не стратегія.» — General Gordon R. Sullivan
Правила: як уникнути фейкових результатів ZFS
Правило 1: Сформулюйте питання перед запуском команди
«Наскільки швидкий цей пул?» — це не питання. Поставте тестоване питання:
- Які sustained random read IOPS на 4k при p99 затримці < 5 ms?
- Яка послідовна швидкість запису для 1M блоків з compression off?
- Яка затримка sync‑запису з SLOG і без нього при concurrency 16?
- Чи зміниться tail‑затримка записів бази даних, якщо змінити recordsize з 128K на 16K?
Запишіть питання. Якщо не можете його сформулювати — не зможете інтерпретувати результат.
Правило 2: Виберіть правильну поверхню тестування: file dataset vs zvol
Тестування file dataset навантажує шлях файлової системи, метадані та recordsize. Тестування zvol навантажує блочний пристрій, volblocksize і інший I/O‑профіль. Бази даних на сирих блоках (або iSCSI) поводяться інакше, ніж бази даних на файлах. Не тестуйте неправильний інтерфейс, а потім не «оптимізуйте» під нього.
Правило 3: Контролюйте кеш або явно вимірюйте його
ARC може зробити читання надприродними. Це нормально, якщо робочий набір у продакшені поміщається в RAM. Якщо ні — ARC‑підсилені тести читання — це художня література продуктивності.
Визначте, що ви тестуєте:
- Cold‑cache performance: що відбувається після перезавантаження або очищення кешу, коли робочий набір >> RAM.
- Warm‑cache performance: стабільна реальність гарячого набору даних. Корисно, але не плутайте з дисковою продуктивністю.
Друге сухе правило: якщо ви не вказали стан кешу в звіті, числа неприйнятні.
Правило 4: Sync‑записи — це окремий всесвіт
Більшість продакшн‑болю походить від sync‑записів: бази даних з fsync, NFS зі sync‑семантикою, VM‑зберігання, що дбає про durabilty. Async‑тести запису можуть виглядати блискуче, поки ваше реальне навантаження не впаде ледве не від відсутності гарантій.
Тестуйте sync експліцитно і включайте процентилі затримки. Якщо є SLOG, тестуйте з ним і без нього. Покажіть витрати на гарантованість даних системи.
Правило 5: Використовуйте steady state; короткі тести брешуть
Поведінка ZFS змінюється з часом: ARC нагрівається, metaslabs розподіляються, фрагментація росте, TXG стабілізуються. Ваш тест має працювати достатньо довго, щоб досягти steady state і зафіксувати хвостову затримку. Як відправну точку:
- Throughput‑тести: 2–5 хвилин на конфігурацію після короткого warm‑up.
- Random latency‑тести: щонайменше 5 хвилин, збирайте p95/p99/p999.
- Порівняння recordsize / compression: повторюйте запуски і порівнюйте розподіли, а не тільки середні.
Правило 6: Усуньте «допоміжні» змінні
Scaling частоти CPU, фонова scrub, resilver, SMART‑тести і шумні сусіди — усе це забруднить результати. Бенчмарки — не час «ввічливо ділитися» машиною. Будьте грубі до решти системи. Потім вибачитесь за uptime.
Правило 7: Не бенчмаркуйте порожні пули і не називайте це продакшеном
Фрагментація й поведінка metaslab змінюються по мірі заповнення пулу. Продуктивність при 5% заповнення може бути відмінною; при 80% — це інша особистість. Якщо вам важливий продакшен, тестуйте на реалістичному рівні заповнення або імітуйте його передвиділенням і churn файлів.
Правило 8: Переконайтеся, що інструмент реально робить I/O
Інструменти можуть обдурити вас. Неправильно налаштований fio може тестувати page cache. dd може тестувати readahead і ефекти кешу. Ваш моніторінг може дивитися на неправильний пристрій.
Довіряй, але перевіряй: під час будь‑якого тесту підтвердіть, що диски показують реальний I/O і що лічильники ZFS рухаються.
Правило 9: Вимірюйте на кількох рівнях
Одне число — пастка. Завжди збирайте щонайменше:
- Рівень застосунка (fio output: IOPS, bw, clat percentiles)
- Рівень ZFS (zpool iostat, arcstat)
- Рівень пристрою (iostat -x: util, await, svctm‑ish сигнали)
- CPU і переривання (mpstat, top)
Коли результати здаються «занадто хорошими», один із цих рівнів буде підозріло тихим.
Правило 10: Міняйте одну річ за раз
Бенчмаркінг — це не фестиваль налаштувань. Якщо ви одночасно змінюєте recordsize, compression, sync і atime — ви займаєтеся генерацією випадкових чисел з додатковими кроками.
Жарт #1: Бенчмаркінг як кулінарія — якщо ви змінили духовку, рецепт і шефа, не хваліться суфле.
Збіг навантаження: файли, блоки, sync і затримка
Архетипи навантажень, що мають значення
Більшість реальних випадків використання ZFS потрапляють у кілька кошиків. Ваш бенчмарк має імітувати один із них:
- Послідовні масові читання: бекапи, медіа, аналітичні скани. Віддавайте перевагу великим блокам, пропускній здатності та prefetch‑ефектам.
- Послідовні масові записи: ingest pipelines, цілі бекапів. Слідкуйте за TXG‑поведінкою і стійкою пропускною здатністю після насичення кешів.
- Випадкові читання: key‑value сховища, VM boot‑шторм. Тут ARC може домінувати; cold‑cache тести важливі.
- Випадкові записи (async): логування, тимчасове сховище. Часто виглядає добре, доки sync не вступає в гру.
- Випадкові записи (sync): бази даних, NFS sync, VM datastore з бар’єрами. Тут головна історія — затримка і поведінка SLOG.
- Навантаження, багате на метадані: git‑сервера, maildirs, CI‑артефакти. Малі файли, операції з каталогами і специфічний vdev можуть мати значення.
Властивості dataset — це не «ручки налаштувань», це контракти навантаження
recordsize, compression, atime, primarycache, logbias і sync — це рішення щодо write amplification, пріоритету кешування і семантики durability. Тестувати їх без розуміння навантаження — означає створити систему, яка виграє бенчмарки, але програє у інцидентах.
Приклад: встановлення recordsize=1M на dataset, що підтримує базу даних, може збільшити overhead read‑modify‑write для 8K оновлень. Ви побачите чудову послідовну пропускну здатність, а потім — стрибки затримки при випадкових оновленнях бази даних. Бенчмарк був «правильний». Питання — ні.
Практичні завдання: команди, виводи, рішення (12+)
Це реальні завдання, які ви можете виконати на хості з ZFS. Кожне включає: команду, що означає вивід, і рішення, яке ви приймаєте. Мета — не зібрати дрібниці, а не довіряти числу, що бреше.
Завдання 1: Підтвердіть топологію пулу і ashift (налаштування «назавжди»)
cr0x@server:~$ sudo zpool status -v tank
pool: tank
state: ONLINE
scan: scrub repaired 0B in 0 days 00:12:41 with 0 errors on Tue Dec 24 03:11:03 2025
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
ata-SAMSUNG_SSD_1 ONLINE 0 0 0
ata-SAMSUNG_SSD_2 ONLINE 0 0 0
ata-SAMSUNG_SSD_3 ONLINE 0 0 0
ata-SAMSUNG_SSD_4 ONLINE 0 0 0
ata-SAMSUNG_SSD_5 ONLINE 0 0 0
ata-SAMSUNG_SSD_6 ONLINE 0 0 0
errors: No known data errors
cr0x@server:~$ sudo zdb -C tank | grep -E 'ashift|vdev_tree' -n | head
67: vdev_tree:
92: ashift: 12
Значення: ashift=12 означає 4K сектори. ashift=9 — це 512B, і на сучасних 4K‑native дисках це може спричинити write amplification і жахливу затримку.
Рішення: Якщо ashift невідповідний для вашого медіа, припиніть «тонування». Плануйте перебудову або міграцію. Інше — косметика.
Завдання 2: Зафіксуйте властивості dataset, що впливають на бенчмарк
cr0x@server:~$ sudo zfs get -o name,property,value -s local,default recordsize,compression,atime,sync,primarycache,logbias tank/test
NAME PROPERTY VALUE
tank/test recordsize 128K
tank/test compression off
tank/test atime off
tank/test sync standard
tank/test primarycache all
tank/test logbias latency
Значення: Тепер ви знаєте, чи «продуктивність» прийшла від compression, чи sync був вимкнений, чи кешування обмежене.
Рішення: Заморозьте ці налаштування для прогону бенчмарку. Будь‑яка зміна вимагає нового запуску і чіткої причини.
Завдання 3: Переконайтеся, що ви випадково не тестуєте page cache
cr0x@server:~$ free -h
total used free shared buff/cache available
Mem: 256G 18G 190G 1.2G 48G 235G
Swap: 0B 0B 0B
cr0x@server:~$ sudo arcstat.py 1 3
time read miss miss% dmis dm% pmis pm% mmis mm% arcsz c
12:01:01 219 3 1 0 0 3 100 0 0 18G 190G
12:01:02 241 2 0 0 0 2 100 0 0 18G 190G
12:01:03 210 4 1 0 0 4 100 0 0 18G 190G
Значення: Видно розмір ARC (arcsz) і хит/міс‑показники. Якщо ваш «дисковий» бенчмарк показує майже нульові misses, вітаємо — ви бенчмаркували RAM.
Рішення: Для cold‑cache чисел або перезавантажуйте між запусками, або використайте робочий набір більший за ARC, або встановіть primarycache=metadata на тестовому dataset (обережно).
Завдання 4: Підтвердіть, що під час прогона відбувається реальний пристрійний I/O
cr0x@server:~$ sudo zpool iostat -v tank 1 3
capacity operations bandwidth
pool alloc free read write read write
---------------------------------------- ----- ----- ----- ----- ----- -----
tank 3.12T 8.77T 120 980 15.0M 980M
raidz2-0 3.12T 8.77T 120 980 15.0M 980M
ata-SAMSUNG_SSD_1 - - 20 165 2.6M 170M
ata-SAMSUNG_SSD_2 - - 19 166 2.4M 169M
ata-SAMSUNG_SSD_3 - - 21 162 2.7M 168M
ata-SAMSUNG_SSD_4 - - 20 161 2.5M 166M
ata-SAMSUNG_SSD_5 - - 20 164 2.4M 169M
ata-SAMSUNG_SSD_6 - - 20 162 2.4M 168M
---------------------------------------- ----- ----- ----- ----- ----- -----
Значення: Ви бачите операції та пропускну здатність по vdev. Якщо fio каже «3 GB/s», а zpool iostat показує 0 MB/s — fio або влучає в кеш, або нічого не робить.
Рішення: Довіряйте zpool iostat для валідації, що тест навантажує пул.
Завдання 5: Перевірте наявність фонових робіт, що отруять результати
cr0x@server:~$ sudo zpool status tank | sed -n '1,25p'
pool: tank
state: ONLINE
scan: scrub in progress since Wed Dec 25 11:48:03 2025
1.11T scanned at 4.52G/s, 220G issued at 898M/s, 3.12T total
0B repaired, 7.03% done, 00:53:12 to go
Значення: Іде scrub. Ваші результати тепер — дует: ваше навантаження плюс scrub I/O.
Рішення: Призупиніть бенчмаркінг. Чи почекайте, чи плануйте тести поза вікнами scrub, або тимчасово зупиніть його, якщо політика дозволяє.
Завдання 6: Встановіть базовий послідовний запис (файли)
cr0x@server:~$ sudo zfs create -o compression=off -o atime=off tank/bench
cr0x@server:~$ fio --name=seqwrite --directory=/tank/bench --rw=write --bs=1M --size=40G --numjobs=1 --iodepth=16 --direct=1 --time_based=1 --runtime=120 --group_reporting
seqwrite: (groupid=0, jobs=1): err= 0: pid=24819: Wed Dec 25 12:03:44 2025
write: IOPS=980, BW=981MiB/s (1029MB/s)(115GiB/120001msec)
clat (usec): min=320, max=18900, avg=2450.11, stdev=702.41
lat (usec): min=340, max=18940, avg=2475.88, stdev=704.13
Значення: direct=1 уникaє page cache. Це базовий тест пропускної здатності, але все одно підлеглий до метаданих ARC і поведінки ZFS. Розподіл затримки важливий; максимальні сплески мають значення.
Рішення: Використовуйте цей базовий результат для порівняння змін (compression, recordsize, layout vdev). Не вважайте його універсальною «швидкістю пулу».
Завдання 7: Random read IOPS з хвостовою затримкою (cold‑ish vs warm)
cr0x@server:~$ fio --name=randread4k --directory=/tank/bench --rw=randread --bs=4k --size=40G --numjobs=4 --iodepth=32 --direct=1 --time_based=1 --runtime=180 --group_reporting --lat_percentiles=1
randread4k: (groupid=0, jobs=4): err= 0: pid=24910: Wed Dec 25 12:09:12 2025
read: IOPS=182k, BW=712MiB/s (747MB/s)(125GiB/180002msec)
clat percentiles (usec):
| 1.00th=[ 118], 5.00th=[ 128], 10.00th=[ 136], 50.00th=[ 176]
| 90.00th=[ 260], 95.00th=[ 310], 99.00th=[ 560], 99.90th=[ 1400]
Значення: Якщо це «cold cache», такі числа вражають і, ймовірно, ARC причетний. Якщо це warm cache — це реалістично для читального навантаження, що вміщується в пам’ять.
Рішення: Повторіть з робочим набором набагато більшим за ARC, якщо потрібна дискова поведінка. Порівнюйте процентилі, а не тільки IOPS.
Завдання 8: Тест sync‑запису (той, що ламає плани)
cr0x@server:~$ sudo zfs set sync=always tank/bench
cr0x@server:~$ fio --name=syncwrite4k --directory=/tank/bench --rw=randwrite --bs=4k --size=10G --numjobs=4 --iodepth=8 --direct=1 --time_based=1 --runtime=180 --group_reporting --lat_percentiles=1
syncwrite4k: (groupid=0, jobs=4): err= 0: pid=25103: Wed Dec 25 12:15:41 2025
write: IOPS=9800, BW=38.3MiB/s (40.2MB/s)(6.73GiB/180002msec)
clat percentiles (usec):
| 50.00th=[ 780], 90.00th=[ 1900], 95.00th=[ 2600], 99.00th=[ 6800]
| 99.90th=[22000]
Значення: Це відображає витрати на гарантованість. Якщо ви очікували 100k IOPS, бо в специфікації SSD так написано — ласкаво просимо до різниці між NAND‑швидкістю і семантикою системи.
Рішення: Якщо p99/p999 надто високі, оцініть якість SLOG, черги та завантаження CPU. Також подумайте, чи дійсно workload потребує sync=always, чи правильність гарантій вже забезпечує застосунок.
Завдання 9: Перевірте, чи є SLOG і чи використовується він
cr0x@server:~$ sudo zpool status tank | sed -n '1,80p'
pool: tank
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
ata-SAMSUNG_SSD_1 ONLINE 0 0 0
ata-SAMSUNG_SSD_2 ONLINE 0 0 0
ata-SAMSUNG_SSD_3 ONLINE 0 0 0
ata-SAMSUNG_SSD_4 ONLINE 0 0 0
ata-SAMSUNG_SSD_5 ONLINE 0 0 0
ata-SAMSUNG_SSD_6 ONLINE 0 0 0
logs
nvme-INTEL_SLOG0 ONLINE 0 0 0
cr0x@server:~$ sudo zpool iostat -v tank 1 3
capacity operations bandwidth
pool alloc free read write read write
---------------------------------------- ----- ----- ----- ----- ----- -----
tank 3.15T 8.74T 10 1200 1.2M 120M
raidz2-0 3.15T 8.74T 10 900 1.2M 90M
logs - - 0 300 0 30M
nvme-INTEL_SLOG0 - - 0 300 0 30M
---------------------------------------- ----- ----- ----- ----- ----- -----
Значення: Під час sync‑навантажень лог‑vdev має показувати записи. Якщо він пасивний — ваше навантаження може не робити sync‑записів, або SLOG неправильно застосований, або ви тестуєте не те, що думаєте.
Рішення: Якщо sync‑продуктивність критична, а SLOG не задіяний — виправте тест або конфігурацію перед тим, як звинувачувати пул.
Завдання 10: Визначте вузькі місця CPU і вплив compression
cr0x@server:~$ mpstat -P ALL 1 3
Linux 6.8.0 (server) 12/25/2025 _x86_64_ (64 CPU)
12:19:01 AM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle
12:19:02 AM all 18.2 0.0 22.9 0.4 0.0 2.1 0.0 0.0 0.0 56.4
12:19:03 AM all 19.0 0.0 24.1 0.5 0.0 2.2 0.0 0.0 0.0 54.2
cr0x@server:~$ sudo zfs set compression=zstd tank/bench
cr0x@server:~$ fio --name=seqwrite-cmpr --directory=/tank/bench --rw=write --bs=1M --size=40G --numjobs=1 --iodepth=16 --direct=1 --time_based=1 --runtime=120 --group_reporting
seqwrite-cmpr: (groupid=0, jobs=1): err= 0: pid=25218: Wed Dec 25 12:20:44 2025
write: IOPS=1500, BW=1501MiB/s (1574MB/s)(176GiB/120001msec)
clat (usec): min=350, max=24100, avg=2600.88, stdev=880.03
Значення: Пропускна здатність покращилася з compression. Це може бути легітимно, якщо ваші продакшн‑дані стиснені подібно. CPU‑використання може зрости; хвостова затримка може змінитися.
Рішення: Перевірте стисливість на реальних зразках даних (або репрезентативних синтетичних). Якщо продакшн‑дані вже стиснуті (медіа, зашифровані блоби), цей бенчмарк не має сенсу.
Завдання 11: Перевірте реальний коефіцієнт стиснення на диску
cr0x@server:~$ sudo zfs get -o name,property,value compressratio,logicalused,used tank/bench
NAME PROPERTY VALUE
tank/bench compressratio 1.72x
tank/bench logicalused 180G
tank/bench used 105G
Значення: compressratio показує те, що сталося, а не те, на що ви сподівались. 1.72x означає, що ви записали менше фізичних даних, ніж логічних.
Рішення: Якщо compressratio близький до 1.00x на репрезентативних даних, не розраховуйте на compression як план продуктивності.
Завдання 12: Проаналізуйте насичення пристроїв і черги
cr0x@server:~$ iostat -x 1 3
Linux 6.8.0 (server) 12/25/2025 _x86_64_ (64 CPU)
Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %util await
nvme0n1 0.0 300.0 0.0 30720.0 0.0 0.0 6.5 0.41
sda 25.0 165.0 2560.0 168960.0 0.0 1.0 78.2 2.90
sdb 24.0 166.0 2450.0 169100.0 0.0 1.0 79.0 2.88
sdc 25.0 162.0 2600.0 168100.0 0.0 1.0 77.5 2.95
Значення: %util близько 100% із зростанням await вказує на насичення пристрою. Якщо диски не завантажені, але затримка висока — вузьке місце десь іще (CPU, блокування, sync, мережа).
Рішення: Якщо диски насичені — оптимізуйте розкладку або додайте vdev. Якщо диски прості — припиніть купувати диски і почніть профілювання стеку.
Завдання 13: Переконайтеся, що тест не обмежений одним файлом або вузьким шляхом метаданих
cr0x@server:~$ fio --name=randread4k-many --directory=/tank/bench --rw=randread --bs=4k --size=40G --numjobs=8 --iodepth=32 --direct=1 --time_based=1 --runtime=180 --group_reporting --filename_format=job.$jobnum.file
randread4k-many: (groupid=0, jobs=8): err= 0: pid=25440: Wed Dec 25 12:28:11 2025
read: IOPS=240k, BW=938MiB/s (984MB/s)(165GiB/180004msec)
clat (usec): min=95, max=3200, avg=210.34, stdev=81.22
Значення: Багато файлів зменшують contention на один файл і можуть виставити паралелізм. Якщо продуктивність значно зростає, попередній тест міг вимірювати вузьке місце, якого в продакшені немає — або навпаки.
Рішення: Виберіть кількість файлів відповідно до реальності: багато файлів для VM‑образів або шардованих БД; менше для великих логів; zvol для блочних робочих навантажень.
Завдання 14: Спостерігайте затримку ZFS під навантаженням (швидка перевірка)
cr0x@server:~$ sudo zpool iostat -r -w tank 1 3
read write
pool ops bandwidth total_wait disk_wait ops bandwidth total_wait disk_wait
tank 120 15.0M 1ms 1ms 980 980M 4ms 3ms
tank 110 14.2M 1ms 1ms 995 990M 5ms 4ms
tank 118 15.1M 2ms 1ms 970 970M 4ms 3ms
Значення: total_wait включає час у чергах ZFS; disk_wait — час на пристрої. Якщо total_wait значно більший за disk_wait — вузьке місце може бути в ZFS scheduling, CPU, contention або sync‑шляху.
Рішення: Використовуйте різницю (total_wait – disk_wait) як підказку: ви чекаєте на диски чи на софт?
Завдання 15: Перевірте вільне місце пулу і ризик фрагментації
cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint tank
NAME USED AVAIL REFER MOUNTPOINT
tank 3.15T 8.74T 128K /tank
cr0x@server:~$ sudo zpool list -o name,size,alloc,free,fragmentation,capacity
NAME SIZE ALLOC FREE FRAG CAP
tank 11.9T 3.15T 8.74T 18% 26%
Значення: Фрагментація і заповненість важливі. По мірі заповнення і фрагментації розподілення ускладнюється, і затримка може зрости.
Рішення: Якщо ви тестуєте при 10–30% заповнення, а в продакшені 80% — ви тестуєте іншу машину. Плануйте тести при реалістичній заповненості.
Швидкий план діагностики
Коли результат бенчмарку виглядає неправдоподібно — або продакшен повільний і ви намагаєтесь відтворити проблему — не починайте випадково міняти властивості ZFS. Замість цього робіть це у такому порядку. Швидко. Детерміновано. Нудно.
Перше: підтвердіть, що тест — це реальний I/O, а не театр кешу
- Перевірте zpool iostat під час тесту. Якщо пропускна здатність пулу близька до нуля — зупиніться.
- Перевірте arcstat miss‑рейт. Якщо misses низькі — ви тестуєте поведінку ARC.
- Переконайтеся, що fio має direct=1 і розмір файлу перевищує RAM, якщо потрібен cold‑cache.
Друге: визначте, чи вузьке місце на дисках, CPU чи в sync‑семантиці
- Запустіть iostat -x. Якщо %util високий і await зростає — пристрої насичені.
- Запустіть mpstat. Якщо %sys високий і CPU зайняті, а диски ні — ви CPU‑bound (checksums, compression, interrupts, locking).
- Примусіть sync‑поведінку на dataset (
sync=always) для короткого тесту. Якщо продуктивність падає і затримка вибухає — ваш вузький шлях — sync і/або SLOG.
Третє: перевірте припущення конфігурації ZFS
- Перевірте топологію (mirror/raidz) і ashift.
- Підтвердіть властивості dataset: recordsize/volblocksize, compression, logbias, primarycache.
- Перевірте фонoві роботи: scrub, resilver, TRIM, snapshots send/receive.
Якщо ви дотримуєтесь цього порядку, зазвичай можна назвати вузьке місце за 5–10 хвилин. Не виправити — назвати. Назвати — перший крок до уникнення хаотичного тонування.
Три корпоративні міні-історії (болісно ймовірні)
Інцидент через хибне припущення: «Це NVMe, отже sync буде ок»
Середня компанія розгорнула нове ZFS‑сховище для віртуальних машин. Воно було all‑flash. Дороге. І мало красивий бенчмарк: випадкові записи були «чудові», і графіки мали стільки кольорів, що годилося б для сучасного мистецтва.
За два тижні ранкові логіни перетворились на повільну катастрофу. VM‑консолі фризили на секунди. Бази даних у VM почали таймаутитись. Команда зберігання зробила те, що команди роблять під тиском: вони знову запустили свій улюблений бенчмарк, побачили чудові числа і заявили, що проблема «в мережі».
Хибне припущення було просте: «All‑flash означає, що sync‑записи будуть швидкі». Їхній бенчмарк використовував async випадкові записи з глибокими чергами і вимірював середню затримку. Продакшен мав багато fsync‑поведінки — журналювання, метадані і flush‑запити гостьових ОС. ZFS трактував це як sync‑записи, і без належного SLOG затримка на шляху гарантій блокувала на гіршій поведінці флешу.
Виправлення не було магією. Вони додали SLOG з захистом від втрати живлення і rerun‑нули бенчмарк з sync=always і процентилями затримки. Числа стали менші, але чесні. Ранкові штормові логіни знову стали нудними, що є найвищою похвалою для системи зберігання.
Оптимізація, що повернулась боком: recordsize і «безкоштовна пропускна здатність»
Аналітична команда хотіла прискорити скани. Хтось прочитав, що «більший recordsize = швидші послідовні читання», і часто це правда. Вони змінили recordsize на 1M у dataset, що містив і паракет‑файли аналітики, і metadata‑сервіс бази даних для відстеження задач і дрібних записів.
Бенчмарки одразу покращилися для масових читань. Вони святкували. Потім метаданний сервіс почав мати стрибки затримки. База даних виконувала дрібні випадкові оновлення, і ZFS мусив керувати великими записами для крихітних модифікацій, що спричинило read‑modify‑write ампліфікацію і додаткові оновлення метаданих. Сервіс не потребував пропускної здатності; йому була потрібна передбачувана дрібна затримка.
Вони «виправили» це, піднявши fio iodepth і concurrency, доки бенчмарк знову не виглядав добре. Це зробило графіки приємнішими, але сервіс гіршим, бо черги ховали затримку, перетворюючи її на backlog.
Справжнє виправлення було нудне: розділити навантаження. Тримати 1M recordsize для аналітики в одному dataset. Поставити базу даних в окремий dataset з меншим recordsize і відповідними sync‑семантиками. Графік пропускної здатності став менш вражаючим; черга інцидентів — меншою. Обирайте свої трофеї.
Нудна, але правильна практика, що врятувала день: вимірювання і документування стану кешу
Фінансова компанія проводила щоквартальні перевірки ємності та продуктивності перед звітними дедлайнами. Це було не гламурно. У них був runbook, що вказував: рівень заповнення пулу, розмір ARC на старті, властивості dataset, файли jobs для fio і як записувати p95/p99 затримку. Кожен прогін включав «cold‑ish» і «warm» тести.
Одного кварталу оновлення firmware на партії SSD внесло кварк затримки при певних глибинах черг. Послідовні числа пропускної здатності не змінилися. Середня випадкова затримка виглядала нормально. Але p99 стрибнув таким чином, що це було видно лише коли кеш був холодним і робочий набір перевищував ARC.
Оскільки у них були послідовні бази, відхилення було очевидним. Вони помітили це до вікна звітності. Повернули firmware і ізолювали партію. Ніяких героїчних дебагів о 2:00, ніяких екстрених закупівель, ніяких «це мережа?» суперечок.
Ця команда ніколи не отримала нагороду за інновацію. Вони отримали те, що краще: безперервний сон.
Поширені помилки: симптом → корінь → виправлення
Тут ваші результати бенчмарку потрапляють на діагностику як хворий сервер: холодні факти, без настрою.
1) Симптом: «Читання неймовірно швидкі, швидші за SSD»
- Корінь: ARC (або OS cache) обслуговує читання. Робочий набір поміщається в RAM, або ви повторили прогін і розігріли кеш.
- Виправлення: Використовуйте
direct=1, збільште розмір dataset за ARC, фіксуйте ARC miss‑rate і явно маркуйте результати «warm‑cache» vs «cold‑cache».
2) Симптом: «Random write IOPS відмінні, але продакшн‑БД повільні»
- Корінь: Бенчмарк використовував async запити; продакшен потребує sync (fsync). Немає SLOG, слабкий SLOG або ви не тестували sync‑шлях.
- Виправлення: Тестуйте з
sync=always, вимірюйте p99, додайте/перевірте SLOG з захистом від втрати живлення і підтвердіть використання черезzpool iostat.
3) Симптом: «Пропускна здатність висока 30 секунд, потім падає»
- Корінь: Ви тестували кеш і буферизацію записів (TXG), а не стійку пропускну здатність пристроїв. Короткі прогони також пропускають steady‑state алокацію.
- Виправлення: Пускайте довші тести, використовуйте time_based прогони з достатньою тривалістю і відстежуйте пропускну здатність пулу з
zpool iostat 1.
4) Симптом: «Затримка стрибає кожні кілька секунд»
- Корінь: TXG commits, sync flush‑поведінка або SLOG latency spikes. Іноді CPU scheduling або interrupt storms.
- Виправлення: Захопіть процентилі fio, корелюйте з
zpool iostat -r -wі перевірте поведінку CPU/переривань. Перевірте якість і firmware SLOG.
5) Симптом: «Зміна compression все робить швидшим, отже покладемось на нього»
- Корінь: Тестові дані стискаються; продакшн‑дані можуть не стискатися (вже стиснуті/зашифровані). Compression маскує межі I/O.
- Виправлення: Перевірте compressratio на репрезентативних даних. Якщо продакшн неcompressible — тестуйте з compression off або з реалістичними даними.
6) Симптом: «Один fio job показує чудові числа; реальний додаток повільніший»
- Корінь: Невідповідність навантаження: розмір блоку, sync‑поведінка, concurrency, патерн доступу, кількість файлів, метадані.
- Виправлення: Створіть fio job‑и, що імітують додаток: ті ж розміри блоків, той самий fsync‑рейт, подібна concurrency, реалістична кількість файлів і змішане читання/запис.
7) Симптом: «Продуктивність пулу нестабільна між прогонами»
- Корінь: Зміна стану кешу, фонова робота (scrub/resilver), зміни рівня заповнення пулу, thermal throttling, зміни CPU governor.
- Виправлення: Контролюйте середовище: ізолюйте хост, зафіксуйте governor, зупиніть фон‑задачі, виконуйте warm‑up і записуйте рівень заповнення та стан ARC кожного прогона.
8) Симптом: «IOPS виглядають добре, але p99 жахливий»
- Корінь: Черги ховають біль. Глубокі iodepth можуть збільшити IOPS, водночас погіршуючи хвостову затримку. Також можлива contention або sync‑стали.
- Виправлення: Тестуйте з різними iodepth, побудуйте графік IOPS vs p99 і оберіть точку, що відповідає latency SLO. Не оптимізуйте лише під IOPS.
Жарт #2: Якщо ваш бенчмарк звітує тільки середні — це по суті гороскоп з кращим форматуванням.
Контрольні списки / покроковий план
Покроково: відтворювана сесія бенчмарку ZFS (продуктивний клас)
- Напишіть питання бенчмарку (throughput vs IOPS vs latency, sync vs async, file vs zvol).
- Зафіксуйте середовище: версія kernel, версія ZFS, модель CPU, RAM, моделі пристроїв, контролер, стан firmware.
- Підтвердіть топологію пулу і ashift (
zpool status,zdb -C). - Створіть виділений dataset для бенчмарків і явно встановіть властивості (compression, atime, sync, recordsize/primarycache).
- Встановіть стан пулу: без scrub/resilver, стабільна температура, стабільний CPU governor, мінімальний шум.
- Вирішіть режим кешу: cold‑ish vs warm. Задокументуйте розмір ARC і misses. Якщо cold‑ish — використайте великий робочий набір і/або перезавантаження між прогонами.
- Warm‑up: запустіть короткий pre‑test, щоб стабілізувати алокацію і уникнути «first touch» аномалій.
- Запустіть бенчмарк достатньо довго для steady state. Захопіть fio output, а також zpool iostat і iostat -x одночасно.
- Повторіть щонайменше 3 рази на конфігурацію. Якщо варіативність велика — у вас шум або недетермінований вузький шлях.
- Змініть одну змінну (recordsize або compression або sync або logbias), перезапустіть той самий пакет тестів.
- Інтерпретуйте на основі кількох рівнів: fio + zpool iostat + iostat -x + CPU‑статистика.
- Прийміть рішення відповідно до вашого SLO: оберіть конфігурацію, що відповідає p99 latency, а не ту, що має найбільшу пікову пропускну здатність.
Шаблон набору тестів: мінімально, але чесно
- Послідовний запис/читання: 1M блоки, 1–4 jobs, iodepth 16, 2 хвилини.
- Випадкове читання: 4k блоки, jobs 4–8, iodepth 16–32, 3 хвилини, процентилі.
- Випадковий запис async: 4k блоки, jobs 4–8, iodepth 8–16, 3 хвилини.
- Випадковий запис sync: те саме, але з
sync=alwaysі виміром p99/p999. - Змішане 70/30 читання/запис: 8k або 16k, процентилі затримки.
FAQ
1) Чи тестувати з compression увімкненим чи вимкненим?
Обидва варіанти, але маркуйте їх. Compression — реальна фіча, що може покращити пропускну здатність і зменшити затримку, виконуючи менше I/O. Вона «фейкова» тільки тоді, коли ваші дані в продакшені не стискаються.
2) Чи підходить dd для бенчмарків ZFS?
Для швидкого послідовного smoke‑тесту — так. Для всього, що включає затримку, випадковий I/O, concurrency або sync‑семантику — використовуйте fio і збирайте процентилі. dd легко випадково тестує кеш і readahead.
3) Що робить sync=disabled для результатів бенчмарку?
Воно може зробити записи значно швидшими, підтверджуючи їх до того, як вони стануть надійними. Це не «трюк налаштування»; це зміна контракту гарантій. Якщо ви використовуєте його в продакшені — ви погоджуєтесь на втрату даних при вимиканні чи краші.
4) Якого розміру мають бути файли для fio?
Для cold‑cache поведінки: більші за ARC (часто більше, ніж RAM). Для warm‑cache: підбирайте під реалістичний робочий набір. Завжди вказуйте, який режим ви тестували.
5) Чому числа змінюються після заповнення пулу?
Алокація ускладнюється, фрагментація зростає, і metaslab‑поведінка змінюється. Продуктивність ZFS при 20% і при 80% заповнення — різні. Якщо вам важливий продакшен — тестуйте при реалістичній заповненості.
6) Чи потрібен мені SLOG?
Лише якщо ваше навантаження видає synchronous записи і ви дбаєте про зменшення sync‑затримки. SLOG не допоможе async‑пропускній здатності і не виправить пул, що вже насичений дисками. Він для sync‑затримки, не для загальної швидкості.
7) Який iodepth обирати у fio?
Використовуйте діапазон. Невеликі черги (iodepth 1–4) показують затримку і чуйність; глибші черги показують максимальну пропускну здатність/IOPS, але руйнують хвостову затримку. Оберіть iodepth, що відповідає concurrency і latency SLO вашого додатку.
8) Як зрозуміти, чи я CPU‑bound у ZFS?
Якщо диски не зайняті (iostat -x %util низький), але latency росте й mpstat показує високий %sys або багато ядер завантажені — швидше за все ви CPU‑bound: checksums, compression, interrupts, шифрування або contention.
9) Чи тестувати raidz і mirror як «просто більше дисків»?
Ні. Mirrors зазвичай мають кращі випадкові IOPS і затримку; raidz економніший за місткість і підходить для послідовних навантажень, але parity і алокація можуть вплинути на дрібні випадкові записи. Тестуйте з реальним профілем навантаження, особливо для випадкових записів і sync‑поведінки.
10) Чи може L2ARC покращити бенчмарки?
Так, але це все ще кеш. Якщо ваше навантаження читальне і повторює дані, L2ARC може допомогти. Якщо навантаження — записне або стрімінгові читання — навряд. Якщо ви тестуєте без вказівки шарів кешу, результати неповні.
Наступні кроки, які ви реально можете зробити
Якщо ви хочете, щоб результати бенчмарків ZFS пережили зіткнення з продакшеном, зробіть три речі цього тижня:
- Задокументуйте і версіонуйте свої fio job‑файли (навіть прості) і зберігайте властивості dataset разом із результатами.
- Додайте стандартну «перевірку істини» до кожного прогона: zpool iostat + arcstat + iostat -x захоплені під час бенчмарку. Якщо рівні не узгоджуються — бенчмарк не підраховується.
- Тестуйте sync‑поведінку з процентилями затримки, навіть якщо думаєте, що вам це не потрібно. Sync — там, де системи припиняють бути швидкими і починають бути чесними.
ZFS здатний на чудову продуктивність. Він також здатний породжувати вражаюче оманливі бенчмарки, якщо ви цього дозволите. Наведені правила — не про перемогу. Вони про те, щоб вас не здивували пізніше — коли здивування приходить з pager’ом.