Ви купили «швидке сховище». У перший день пул добре показував себе на тестах. Через місяць бази даних починають
вести себе так, ніби кожен запит пробирається крізь в’язкий цемент. Grafana показує підвищену латентність.
Команда додатку звинувачує мережу. Мережники кажуть «не ми». Ви запускаєте zpool iostat — і ось воно:
один vdev сидить у кутку, червоніє, потіє і тягне весь пул, ніби тягне диван вгору трьома поверхами.
ZFS напрочуд справедливий і напрочуд безжальний. Він використовує всі vdev… поки один не відстає.
Тоді пул фактично синхронізується за найповільнішим учасником, особливо для записів та навантажень, чутливих до латентності.
Це не історія «ZFS поганий». Це історія «фізика груба» — плюс кілька архітектурних виборів,
які ви можете використати, зловживати або виправити.
Що насправді означає «дисбаланс vdev» (і що ні)
У ZFS пул — це колекція vdev. Vdev — атомарна одиниця розподілу сховища: ZFS рівномірно розподіляє
дані по vdev, а не по окремих дисках (з важливим застереженням, що RAIDZ або mirror vdev внутрішньо використовує кілька дисків).
«Дисбаланс vdev» — це коли один vdev виконує непропорційно багато роботи або завершує її набагато повільніше,
так що пул загалом обмежується латентністю або пропускною здатністю. Це може бути:
- Дисбаланс продуктивності: vdev A має вищу латентність/нижчі IOPS ніж vdev B при подібному навантаженні.
- Дисбаланс розподілу: vdev A значно заповнений/більш фрагментований, тому нові виділення важчі й повільніші.
- Дисбаланс навантаження: «спеціальні» ролі (SLOG, special vdev, патерни метаданих L2ARC) спрямовують I/O до підмножини пристроїв.
- Дисбаланс через режим відмови: один пристрій повторює операції, перемаповує сектора або тихо відмирає, і ви платите за це хвостовою латентністю.
Чого це зазвичай не означає: що ZFS «випадково любить» якийсь vdev. ZFS керується правилами. Якщо один vdev повільніший, більш заповнений,
більш фрагментований або має помилки, ZFS продовжить посилати I/O, і користувацька латентність пулу стане сумою тисяч маленьких «чекань на повільний».
Сухий гумор #1: Повільний vdev — це як статусна нарада, яка «займе лише п’ять хвилин» — ви все одно будете там о 11:30.
Як ZFS розподіляє ввід/вивід між vdev
Пул — це стріп на рівні vdev, а не магічний суп продуктивності
Базова модель для здорового глузду: ZFS розподіляє блоки по vdev і зазвичай намагається тримати вільний простір збалансованим (з вагуванням) між ними.
Коли у вас кілька верхніх vdev, пул поводиться як stripe на шарі vdev. Для багатьох навантажень це означає, що пропускна здатність масштабується
залежно від кількості vdev. Але це також означає, що пул успадковує найгіршу поведінку латентності будь-якого vdev, що бере участь у навантаженні.
Рішення про розміщення: metaslab, space map і преференція «меншого зла»
ZFS ділить vdev на metaslab. Metaslab мають space maps, і ZFS використовує евристики для вибору місця розміщення нових блоків.
Він віддає перевагу metaslab з більшим вільним простором і кращими характеристиками виділення. З часом фрагментація і заповненість змінюють вартість алокації.
Дві важливі наслідки:
-
Коли vdev заповнюються, виділення стають дорожчими й більш фрагментованими. Vdev з використанням 80–90% може стати помітно повільнішим,
ніж vdev з 40–60%, навіть якщо диски ідентичні. -
«Збалансований вільний простір» ≠ рівна продуктивність. ZFS може тримати вільне місце приблизно рівним,
але не може вирівняти поведінку фізичних пристроїв, прошивок або прихованих помилок носія.
Читання проти записів: чому болить саме при записах
Читання часто мають більше «шляхів втечі»: кеш ARC, prefetch, вплив стиснення і можливість того, що «гарячі» дані випадково або політично зосереджені
на швидшому vdev. Записи мають менше виходів. Коли додаток чекає на синхронний запис, найповільніше посилання стає всією ланцюжком.
Спеціальні vdev, SLOG і проблема «воронки продуктивності»
Деякі функції ZFS навмисно направляють певні I/O на конкретні пристрої:
- SLOG (окремий журнал) для синхронних записів (ZIL). Чудово, якщо він швидкий і захищений від втрати живлення; катастрофа, якщо повільний або перевантажений.
- Special vdev для метаданих і (опціонально) малих блоків. Чудово, якщо правильно забезпечений; вузьке місце, якщо замалий або повільніший за основні vdev.
- L2ARC для кешування читань. Безпосередньо не гальмує записи, але може змінити патерни читань і приховати проблеми до збою кешу.
Якщо ви спроєктували воронку — ви відповідаєте за неї. Поставте внизу повільний пристрій — і ви побудуєте машину латентності.
Чому один повільний vdev шкодить усьому пулу
Хвостова латентність — справжній обмежувач пулу
Обговорення продуктивності сховищ люблять середні величини, бо вони ввічливі. Промислові системи живуть у відсотках (percentiles),
бо вони чесні. Якщо один vdev має періодичні сплески 200–800 мс через повтори прошивки, SMR-шінгінг, або насичення черги контролера,
ці сплески поширюються.
ZFS не чекає синхронно «на всіх» для кожного блоку в пулі. Але огляд латентності вашого додатку все ще формується
найповільнішим I/O, від якого він залежить: коміти транзакційних груп, скидання логів синхронних записів, оновлення метаданих,
непрямі блоки та малі випадкові I/O, де паралелізм обмежений.
RAIDZ і mirror: внутрішня геометрія має значення
Верхній vdev може бути mirror, RAIDZ1/2/3 або одиночним диском (не варто). Якщо один диск всередині RAIDZ vdev сповільнюється —
бо він виходить з ладу, бо це SMR, бо він за дивним експандером — тоді латентність усього RAIDZ vdev може вирости.
Ви не можете «пропустити» повільний диск; паритетні обчислення та операції реконструкції — групові дії.
Mirror поводяться інакше: читання може обслуговуватись з будь-якого боку (ZFS вибирає за евристикою), але записи мають піти на обидва.
Один відсталій учасник mirror підвищує латентність запису для mirror vdev.
Планувальник пулу не перетворить поганий vdev на хороший
ZFS може розумно чергувати I/O. Він може видавати більше на швидкі vdev. Він може розподіляти виділення.
Він не може зробити повільний пристрій швидким і не може прибрати закони фізики. Коли навантаження містить синхронні записи,
залежності метаданих або обмежену кількість одночасних запитів, один повільний vdev стає метрономом для пулу.
Парафразована ідея (цитата про надію)
Парафразована ідея: надія — не стратегія
— Gene Kranz, flight director (широко цитують в опер-культурі; формулювання варіюється).
У сфері зберігання даних «надіятись, що повільний vdev перестане бути повільним» — це не план відновлення. Це лише питання часу.
Факти та історичний контекст, які корисні в дискусіях
- ZFS виник у Sun Microsystems у середині 2000-х з основною метою: цілісність даних end-to-end через контрольні суми та copy-on-write.
- Концепція «vdev як одиниця алокації» є свідомою: вона спрощує домени відмов і моделювання продуктивності порівняно з пер-дисковим стрипінгом.
- Початкові розгортання ZFS схилялися до RAIDZ щоб зменшити «діру RAID5» і покращити цілісність; компроміси продуктивності завжди були частиною угоди.
- Сучасний OpenZFS додав «special vdev» щоб прискорити метадані/малі блоки на SSD; це може стати революційним — або перетворитись на вузьке місце.
- ARC кеш ZFS передував епосі SSD повсюдно; багато скарг «ZFS повільний» насправді означають «моє робоче навантаження більше не в ARC».
- SMR-диски змінили ландшафт відмов: вони можуть виглядати нормальними, поки випадкові записи або тривалі оновлення не спричинять поведінку read-modify-write і стрибки латентності.
- 4K сектора і ashift стали довгостроковим податком на продуктивність: неправильний ashift незворотний для того vdev і може непомітно знизити швидкість запису.
- Scrub ZFS — це проєктне рішення, а не необов’язкова марнотратність: регулярні scrubs знаходять латентні помилки раніше, ніж вони стають причиною великої реконструкції.
- Таймаути пристрою та повтори — прихований ворог: навіть невелика кількість повторів може домінувати у хвостовій латентності і досвіді користувача.
Швидкий план діагностики (перевірити перше/друге/третє)
Перше: підтвердіть, що це вузьке місце vdev, а не підроблена інформація від додатку
- Запустіть
zpool iostat -vз колонками латентності, якщо вони доступні на вашій платформі, і дивіться, який vdev має найгірший await або найдовший час обслуговування. - Перевірте, чи пул виконує scrub/resilver. Якщо так — перестаньте гадати: ваша базова лінія продуктивності вже недійсна.
- Підтвердьте тип навантаження: sync writes, малі випадкові читання, послідовний стрімінг або інтенсивні операції з метаданими. Прояви «повільного vdev» різняться.
Друге: ізолюйте, чому vdev повільний — зайнятий, ламається чи структурно вразливий
- Зайнятий: висока завантаженість, велика глибина черги, стабільно висока швидкість I/O.
- Ламається: середня швидкість I/O, але величезні стрибки латентності, накопичення помилок, скиди лінків, таймаути.
- Структурно вразливий: значно заповнений порівняно з іншими, undersized special vdev, неправильний ashift, змішання SMR з CMR, маленький recordsize що призводить до голоду IOPS.
Третє: вирішіть, чи можна виправити на льоту або потрібна перебудова/міграція
- Живе виправлення: заміна пристрою, видалення лог-пристрою, додавання vdev, налаштування властивостей dataset, ребаланс через перезапис даних.
- Перебудова/міграція: неправильний тип vdev, неправильний ashift, змішане медіа, що завжди поводитиметься погано, special vdev замалий і його безпечне розширення вимагає редизайну.
Сухий гумор #2: RAIDZ не переймається вашими відчуттями, лише бюджетом IOPS.
Практичні завдання: команди, виводи, рішення (12+)
Завдання 1: Визначити повільний vdev під реальним навантаженням
cr0x@server:~$ zpool iostat -v 2 5
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 18.2T 7.45T 8200 4100 780M 420M
raidz2-0 9.10T 3.72T 4100 2000 390M 205M
sda - - 1100 520 105M 54.0M
sdb - - 1000 510 95.0M 53.5M
sdc - - 950 500 92.0M 52.0M
sdd - - 1050 520 98.0M 54.0M
sde - - 1000 510 95.0M 52.5M
sdf - - 1000 510 95.0M 53.0M
raidz2-1 9.10T 3.73T 4100 2100 390M 215M
sdg - - 1050 540 98.0M 55.0M
sdh - - 1000 530 95.0M 54.0M
sdi - - 200 520 18.0M 53.0M
sdj - - 1050 540 98.0M 55.0M
sdk - - 1000 530 95.0M 54.0M
sdl - - 1000 530 95.0M 54.0M
Що це означає: Диск sdi робить значно менше читань, ніж його «побратими». Це може означати, що він повільний, має помилки
або піддається повторним спробам, через які планувальник уникає його для читань.
Рішення: Терміново перевірте SMART та системні журнали для sdi, перевірте кабелі/шляхи контролера.
Якщо це учасник mirror — розгляньте заміну; якщо в RAIDZ — очікуйте, що в час реконструкції весь vdev постраждає.
Завдання 2: Перевірити стан пулу та накопичення помилок
cr0x@server:~$ zpool status -v tank
pool: tank
state: ONLINE
status: One or more devices has experienced an unrecoverable error.
action: Replace the device or clear the errors.
scan: scrub repaired 0B in 12:41:20 with 0 errors on Tue Dec 24 03:12:51 2025
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
sda ONLINE 0 0 0
sdb ONLINE 0 0 0
sdc ONLINE 0 0 0
sdd ONLINE 0 0 0
sde ONLINE 0 0 0
sdf ONLINE 0 0 0
raidz2-1 ONLINE 0 0 0
sdg ONLINE 0 0 0
sdh ONLINE 0 0 0
sdi ONLINE 3 0 0
sdj ONLINE 0 0 0
sdk ONLINE 0 0 0
sdl ONLINE 0 0 0
errors: Permanent errors have been detected in the following files:
/tank/vmstore/vm-104-disk-0
Що це означає: sdi має помилки читання. Також є постійні помилки у файлі: механізм контрольних сум/ремонту не зміг повністю відновити.
Рішення: Ставте sdi під підозру. Замініть його, а потім відновіть уражені дані з резервних копій або реплік. Не «очищайте і сподівайтесь», поки не зрозумієте вплив.
Завдання 3: Перевірити, чи scrub/resilver маскує звичну поведінку
cr0x@server:~$ zpool status tank
pool: tank
state: ONLINE
scan: resilver in progress since Wed Dec 25 01:10:02 2025
3.22T scanned at 1.14G/s, 920G issued at 322M/s, 18.0T total
920G resilvered, 5.00% done, 0:46:10 to go
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
raidz2-1 ONLINE 0 0 0
Що це означає: Ви в зоні resilver. Скарги щодо продуктивності під час resilver очікувані; важливо, чи один vdev непропорційно повільніший.
Рішення: Якщо ваша SLA страждає, плануйте resilver/scrub у вікна з низьким трафіком і переконайтеся, що ashift, клас пристрою і шляхи контролера
не створюють однополосну магістраль.
Завдання 4: Підтвердити, чи один vdev значно заповнений
cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint tank
NAME USED AVAIL REFER MOUNTPOINT
tank 18.2T 7.45T 192K /tank
cr0x@server:~$ zpool list -v tank
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH
tank 25.6T 18.2T 7.45T - - 38% 70% 1.00x ONLINE
raidz2-0 12.8T 9.10T 3.72T - - 31% 70% - ONLINE
raidz2-1 12.8T 9.10T 3.73T - - 46% 70% - ONLINE
Що це означає: Обидва vdev мають подібну алокацію, але фрагментація різниться: raidz2-1 більш фрагментований.
Рішення: Очікуйте вищих накладних витрат на алокацію і гіршої хвостової латентності на більш фрагментованому vdev.
Якщо фрагментація висока й стійка — плануйте стратегію переписування/ребалансування (send/recv або міграція датасетів).
Завдання 5: Спіймати патерн «пристрій повторює» в системних логах
cr0x@server:~$ dmesg -T | egrep -i "ata|scsi|nvme|reset|timeout|error" | tail -n 20
[Wed Dec 25 02:13:21 2025] sd 6:0:12:0: [sdi] tag#1034 FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE
[Wed Dec 25 02:13:21 2025] sd 6:0:12:0: [sdi] Sense Key : Medium Error [current]
[Wed Dec 25 02:13:21 2025] sd 6:0:12:0: [sdi] Add. Sense: Unrecovered read error
[Wed Dec 25 02:13:22 2025] blk_update_request: I/O error, dev sdi, sector 7814037096 op 0x0:(READ)
[Wed Dec 25 02:13:25 2025] ata12.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x6 frozen
[Wed Dec 25 02:13:26 2025] ata12.00: failed command: READ FPDMA QUEUED
[Wed Dec 25 02:13:27 2025] ata12: hard resetting link
Що це означає: Жорсткі скиди й невідновні помилки читання створюють довгі простої. Навіть якщо ZFS «лікує» читання, ви сплачуєте за це латентністю та блокуванням черг.
Рішення: Замініть пристрій і перевірте весь шлях: прошивку HBA, експандер, бекплейн, кабелі. Якщо кілька дисків показують скиди — підозрюйте шлях.
Завдання 6: Витягнути SMART/NVMe стан і шукати «помираючі тихо» лічильники
cr0x@server:~$ smartctl -a /dev/sdi | egrep -i "realloc|pending|uncorrect|offline|error|timeout|crc"
5 Reallocated_Sector_Ct 0x0033 098 098 010 Pre-fail Always - 24
197 Current_Pending_Sector 0x0012 100 100 000 Old_age Always - 6
198 Offline_Uncorrectable 0x0010 100 100 000 Old_age Offline - 6
199 UDMA_CRC_Error_Count 0x003e 200 200 000 Old_age Always - 34
Що це означає: Pending/uncorrectable сектори вказують на проблеми з носієм. CRC-помилки зазвичай вказують на проблеми з кабелем/бекплейном.
Рішення: Якщо CRC зростає — пересуньте/замініть кабель/бекплейн і спостерігайте. Якщо є pending/uncorrectable — заплануйте заміну. Не домовляйтеся з ентропією.
Завдання 7: Перевірити, чи синхронні записи прив’язані до повільного або відсутнього SLOG
cr0x@server:~$ 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
raidz2-1 ONLINE 0 0 0
logs
nvme0n1p2 ONLINE 0 0 0
Що це означає: Є виділений лог-пристрій. Якщо латентність синхронного запису жахлива — цей пристрій підозрілий або просто насичений.
Рішення: Виміряйте латентність на лог-vdev окремо (iostat, smart, nvme). Якщо це споживацький NVMe без захисту при втраті живлення, перегляньте рішення: безпека даних і стрибки латентності — не опціональні.
Завдання 8: Виявити special vdev і чи він стає вузьким місцем
cr0x@server:~$ zpool status tank | sed -n '1,120p'
pool: tank
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
raidz2-1 ONLINE 0 0 0
special
mirror-2 ONLINE 0 0 0
nvme1n1p1 ONLINE 0 0 0
nvme2n1p1 ONLINE 0 0 0
Що це означає: Метадані (і можливо малі блоки) розміщені на special vdev. Якщо він повільний, весь пул відчуває повільність — особливо навантаження з великою часткою метаданих.
Рішення: Перевірте властивості dataset, як-от special_small_blocks. Переконайтеся, що special vdev має достатній запас ємності та порівнянну витривалість/латентність для вашого навантаження.
Завдання 9: Переглянути налаштування датасету, що можуть посилювати дисбаланс vdev
cr0x@server:~$ zfs get -o name,property,value -s local recordsize,compression,atime,sync,logbias,special_small_blocks tank/vmstore
NAME PROPERTY VALUE
tank/vmstore recordsize 16K
tank/vmstore compression lz4
tank/vmstore atime off
tank/vmstore sync standard
tank/vmstore logbias latency
tank/vmstore special_small_blocks 16K
Що це означає: Малий recordsize разом із special_small_blocks=16K означає, що багато блоків потрапляють на special vdev.
Це нормально, якщо special vdev швидкий і просторий.
Рішення: Якщо special vdev майже повний або має велику латентність — зменшіть special_small_blocks (або відключіть),
або переробіть архітектуру: додайте більше special ємності, швидші пристрої або змініть recordsize під навантаження.
Завдання 10: Квантифікувати латентність vdev безпосередньо через статистику пристрою
cr0x@server:~$ iostat -x 2 3
Linux 6.8.0 (server) 12/25/2025 _x86_64_ (32 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
9.21 0.00 3.14 7.88 0.00 79.77
Device r/s w/s rkB/s wkB/s aqu-sz await r_await w_await svctm %util
sda 95.0 52.0 97280 53248 1.2 10.5 9.8 11.7 2.1 31.0
sdi 18.0 50.0 18432 51200 14.8 214.2 390.1 62.3 6.8 97.0
nvme0n1 620.0 410.0 640000 420000 0.9 1.4 1.2 1.7 0.2 18.0
Що це означає: sdi має велике await і майже 100% використання з глибокою чергою. Це класичний симптом повільного vdev.
Рішення: Якщо це стабільно — замініть/евакуйте диск або виправте шлях. Якщо це сплески — дивіться фоні процеси (scrub, backup, snapshots) або поведінку SMR.
Завдання 11: Перевірити ashift, щоб виявити постійні помилки вирівнювання
cr0x@server:~$ zdb -C tank | egrep -i "vdev_tree|ashift" -n | head -n 30
54: vdev_tree:
78: ashift: 12
141: ashift: 9
Що це означає: Змішані значення ashift у пулі — це запах проблем. Ashift 9 (512B) на дисках з 4K-native може спричинити штрафи read-modify-write.
Рішення: Якщо ви знайдете неправильний ashift — його не «налаштувати» пізніше. Плануйте заміну vdev або міграцію. Не будуйте нові пули без явного встановлення ashift, якщо вам важлива прогнозована продуктивність.
Завдання 12: Виявити серйозну фрагментацію та патологію алокацій
cr0x@server:~$ zpool list -o name,size,alloc,free,frag,cap,health tank
NAME SIZE ALLOC FREE FRAG CAP HEALTH
tank 25.6T 18.2T 7.45T 38% 70% ONLINE
Що це означає: Фрагментація не завжди фатальна, але коли вона зростає разом із заповненістю пулу, випадкові операції запису сильно страждають.
Рішення: Якщо FRAG високий і продуктивність страждає — плануйте цикл переписування (send/recv на свіжий пул або міграцію датасетів) замість нескінченного тонкого налаштування.
Завдання 13: Подивитися, чи один vdev робить непропорційний I/O у часі
cr0x@server:~$ zpool iostat -v -l 5 3
operations bandwidth total_wait
pool read write read write read write
------------------------- ---- ----- ----- ----- ----- -----
tank 8200 4100 780M 420M 12ms 28ms
raidz2-0 4100 2000 390M 205M 8ms 16ms
raidz2-1 4100 2100 390M 215M 45ms 82ms
------------------------- ---- ----- ----- ----- ----- -----
Що це означає: raidz2-1 має значно вищий час очікування, ніж raidz2-0 при подібній пропускній здатності. Це дисбаланс на рівні vdev, а не випадковість.
Рішення: Ретельно перегляньте пристрої всередині raidz2-1. Якщо вони здорові — підозрівайте заповненість/фрагментацію, шлях контролера або змішання моделей/прошивок дисків.
Завдання 14: Визначити, хто генерує I/O (бо «сховище повільне» — це не процес)
cr0x@server:~$ zpool iostat -v 1
...output...
cr0x@server:~$ iotop -oPa
Total DISK READ: 145.20 M/s | Total DISK WRITE: 81.33 M/s
PID USER DISK READ DISK WRITE SWAPIN IO> COMMAND
23144 root 90.12 M/s 1.23 M/s 0.00 % 22.14 % /usr/sbin/zfs receive -u tank/vmstore
18201 postgres 8.10 M/s 45.77 M/s 0.00 % 10.31 % postgres: checkpointer
Що це означає: zfs receive записує інтенсивно, а Postgres виконує checkpointer. Це може створити хвилі синхронних записів і метаданого навантаження.
Рішення: Якщо це планова реплікація — обмежте швидкість або розплануйте. Якщо непланова — знайдіть власника завдання. Потім налаштуйте датасети (recordsize, sync) відповідно, а не емоційно.
Типові режими відмов, що створюють дисбаланс vdev (реальні випадки)
1) Змішане медіа або змішання класів поведінки дисків
Змішування моделей HDD, які на папері схожі, може створити дисбаланс vdev через різну прошивку і поведінку кешу.
Змішання CMR і SMR дисків гірше: SMR може показувати величезні стрибки латентності під стійкими випадковими записами або під час фонової очистки.
Змішування SATA і SAS за різними експандерами також може створити ефект «один vdev нормальний, інший — наче проклятий».
Якщо ваш пул має два RAIDZ vdev і один з них зібраний з «того, що було» — у вас не пул, а експеримент.
Для продакшену експерименти не потрібні.
2) Один проблемний диск всередині RAIDZ або mirror
ZFS тримає vdev онлайн, поки диск кульгає з повторними спробами. Це добре для доступності. Натомість це погано для латентності.
Диск може бути «достатньо здоровим», щоб не вийти з ладу, але настільки повільним, щоб зруйнувати хвостову латентність. Це часто трапляється через:
- Зростання кількості Reallocated/Pending секторів
- CRC-помилки інтерфейсу від ненадійного кабелю/бекплейна
- Термічне тротлінгування в щільних шасі
- Баги прошивки, що викликають періодичні скиди
3) Special vdev замалий або повільний
Special vdev — це множник продуктивності, якщо зроблено правильно, і вузьке місце для всього пулу, якщо неправильно.
Метадані малі, але постійні. Якщо ви покладаєте малі блоки на special, а потім запускаєте VM-образи з 8K–16K блоками,
ваш special vdev стає шляхом запису для великої частини навантаження.
Якщо special vdev заповнюється, він перестає приймати алокації і ви отримаєте некрасиву поведінку. Більш тонко: навіть до заповнення,
якщо він повільніший за основні vdev (або просто насичений), ви відчуєте латентність, як на special vdev.
4) Неправильний ashift: постійний борг продуктивності
Невирівняні записи створюють цикли read-modify-write на диску. Це не налаштовувана прикрість, це архітектурний брак.
Якщо один vdev має неправильний ashift, він може поводитися як повільний vdev назавжди, навіть коли пристрої ідентичні.
5) Фрагментація + висока заповненість пулу
Фрагментація ZFS не дорівнює традиційній фрагментації файлової системи, але ефект схожий: більше пошуків, більше метаданих,
більше дрібних I/O. RAIDZ особливо чутливий до малих випадкових записів через паритетну математику і ампліфікацію RMW.
При високій заповненості вибір metaslab обмежується, і аллокатор обирає «найменш поганий» варіант.
6) Фонова робота, про яку ви забули
Scrub, resilver, видалення snapshot, отримання реплікацій і важке стискування можуть домінувати над I/O. Поширена ситуація:
один vdev трохи слабший, туди накопичуються фонова робота, він стає ще слабшим, і так замикається позитивний зворотний зв’язок.
Вітаємо, ви створили петлю самопідсилення.
Три міні-історії з корпоративного життя (анонімізовано, правдоподібно, технічно коректно)
Міні-історія 1: Інцидент через неправильне припущення
Середня компанія експлуатувала кластер віртуалізації на пулі ZFS: два верхніх RAIDZ2 vdev, по шість дисків.
Команда припустила, що «однакова ємність» означає «однакова продуктивність». Один vdev був збудований із трохи новішої партії дисків
з іншою лінійкою прошивки. Закупівля сказала «еквівалентно». Так не було.
У синтетичних тестах все виглядало добре: послідовна пропускна здатність була чудова. Потім настала робоча неділя — бум завантажень VM,
логіни та база даних, яка ненавиділа малі випадкові читання. Латентність виросла і залишилася високою.
Додаткова команда бачила таймаути. Команда зберігання не бачила нічого «впавшого». Пул був ONLINE, scrubs проходили, життя здавалося зеленим.
Прорив настав, коли визнали, що здоров’я і продуктивність — різні стани. zpool iostat -v показав один vdev
з постійно вищими часами очікування під час піків випадкових читань. Per-disk iostat -x і журнали ядра показали періодичні
скиди лінка лише на двох дисках — достатньо, щоб гальмувати RAIDZ-групу.
Виправлення не було хитрим ZFS-параметром. Воно було нудним: заміна підозрілих дисків і, що важливіше, ремонт шляху SAS,
який спричиняв скиди. Також змінили стандарти збірки: кожен vdev має бути гомогенним за моделлю/прошивкою, і кожен шлях HBA/backplane
має валідовано працювати під навантаженням перед введенням у продакшен.
Неправильне припущення було тонким: «ZFS балансуватиме між vdev, тож один трохи дивний vdev не має значення».
ZFS збалансовував алокації чудово. Навантаження не переймалося справедливістю — воно переймалося хвостовою латентністю.
Міні-історія 2: Оптимізація, що обернулася проти
Інша команда мала пул для домашніх директорій і артефактів CI. Оскільки метадані запитувались часто, вони додали special vdev
на парі споживчих NVMe. Спочатку було швидко. Так швидко, що почали називати це «SSD turbo mode» — фраза, яка має викликати рев’ю ризиків.
Команда включила special_small_blocks широко, бо це пришвидшило CI-джоби. Потім склад датасетів змінився:
більше дрібних файлів, більше шарів контейнерів, більше дрібних випадкових записів. Special vdev став і сховищем метаданих, і сховищем малих блоків.
Набір зношення виріс. Латентність почала хитатися. Ніхто не помічав — ARC і L2ARC маскували читання, а записи «зазвичай» виконувались швидко.
Через місяці сплеск синхронних записів у пікові години вивів на світло слабкість. Споживчі NVMe почали тротлити через тепло та тривалі записи.
Пул не впав. Він просто відчувався як збій: шелл зависав, збірки таймаутили і всі звинувачували CI.
Постмортем був чесним: вони оптимізували не те. Вони ставилися до special vdev як до кешу (опціональний, best-effort).
Це не кеш. Це первинне сховище для того, що на ньому лежить. Виправлення включало переміщення малих блоків назад на основні vdev для більшості датасетів,
покращення охолодження і перебудову special vdev на пристроях enterprise-класу з захистом від втрати живлення.
Провал стався не тому, що special vdev поганий. Він підвів, бо зробили його критичним шляхом і побудували як іграшку.
Міні-історія 3: Нудна, але правильна практика, що врятувала ситуацію
Фінансова команда експлуатувала NFS на ZFS для аналітики й користувацьких шарів. Вони мали ритуал: щотижневий scrub,
щомісячний перегляд SMART-трендів і правило, що будь-який диск зі зростаючими CRC або pending-секторами замінюється в робочий час.
Не тому, що він вже помер, а тому, що вони не люблять сюрпризів.
Одного четверга латентність почала повільно зростати. Не стрибками — просто поступовий підйом. На черзі перевірив zpool iostat і побачив,
що час очікування одного vdev росте. zpool status був чистим. Немає помилок. Все ONLINE. Багато команд на цьому зупиняються.
Їхня «нудна» практика спрацювала: витягнули SMART для всього шасі і знайшли один диск зі скромним, але постійним зростанням
UDMA_CRC_Error_Count. Це не кричало «замініть». Це шепотіло «кабель ненадійний». Вони пересунули кабель, помилки перестали зростати,
і латентність нормалізувалась без драм.
За два дні, під час планового вікна, вони замінили кабельний жгут і перевірили схематику бекплейн-ланцюжків. Жодного простою, жодних втрат даних, жодного пейджера о півночі.
Пул ніколи не став DEGRADED. Ось у чому суть: найкращий інцидент — той, що ніколи не стає тикетом.
Типові помилки: симптом → корінь → виправлення
1) «Пропускна здатність пулу нормальна, але латентність жахлива»
Симптом: Великі послідовні копії виглядають швидкими; бази даних і VM I/O застоюються; p99 латентність стрибає.
Корінь: Один vdev/пристрій має високу хвостову латентність (повтори, тротлінг, SMR), або special vdev/SLOG насичений.
Виправлення: Визначте повільний vdev за допомогою zpool iostat -v + iostat -x. Замініть/відремонтуйте слабкий компонент.
Перевірте розміри special vdev і клас пристроїв.
2) «Один vdev показує більший час очікування, хоча диски ідентичні»
Симптом: Два RAIDZ vdev, однакова модель дисків, але один постійно повільніший.
Корінь: Різний шлях контролера, експандер, налаштування черг або один проблемний диск усередині vdev.
Виправлення: Перевірте журнали ядра на скиди, перевірте кабелі/бекплейн, порівняйте per-disk await/%util. Поміняйте диски місцями для перевірки.
3) «Scrub/resilver йде вічно і продуктивність падає»
Симптом: ETA resilver скачуть; користувацький I/O пригальмовує під час скану.
Корінь: Слабкий диск або насичений vdev; висока фрагментація; одночасне важке навантаження; SMR-диски.
Виправлення: Зменшіть конкуренцію навантаження, пріоритезуйте вікно ремонту і замініть повільні диски. Якщо є SMR — плануйте міграцію; не сперечайтеся.
4) «Після додавання нового vdev нічого не прискорилось»
Симптом: Додали ємність/IOPS, але продуктивність лишається обмеженою.
Корінь: Існуючі блоки залишилися на старих vdev; алокаційні евристики не роблять ретроспективного ребалансингу; гарячий набір даних не перемістився.
Виправлення: Ребалансуйте шляхом переписування даних (send/recv, rsync на новий датасет або міграція VM). Не чекайте дива від «додати vdev».
5) «Метадатичне навантаження повільне, але диски здаються вільними»
Симптом: Повільні операції з директоріями, малі файли, розгортання контейнерів; %util дисків не шалений.
Корінь: Special vdev перевантажений або майже повний; тиск на ARC викликає постійні пропуски метаданих; невідповідний recordsize.
Виправлення: Перегляньте використання special vdev, статистику ARC і властивості датасетів. Розширте або переробіть special vdev; відрегулюйте special_small_blocks і recordsize.
6) «Випадкова продуктивність запису впала після того, як пул досяг ~80%»
Симптом: Те саме навантаження, але гірша продуктивність з часом; без змін у апаратурі.
Корінь: Фрагментація + обмеження аллокатора + ампліфікація малих записів в RAIDZ.
Виправлення: Тримайте пули з запасом для випадкових записів, або плануйте періодичну переписку/міграцію. Налаштування не розфрагментує vdev.
Контрольні списки / покроковий план
Коли спрацьовують тривоги по латентності: 15-хвилинна триаж
- Запустіть
zpool status. Якщо scrub/resilver активний — зафіксуйте інцидент і скоригуйте очікування. - Запустіть
zpool iostat -v 2 5. З’ясуйте, який vdev повільний (дисбаланс wait/throughput) і який диск аномальний. - Запустіть
iostat -x 2 3. Підтвердіть високий await/%util на підозрілих пристроях. - Перегляньте
dmesgна предмет скидів/таймаутів. Якщо вони є — припиніть дебати; виправте шлях або замініть диск. - Витягніть SMART/NVMe стан. Шукайте pending/uncorrectable і тенденції CRC.
- Якщо задіяні синхронні записи — перевірте стан SLOG і навантаження. Якщо багато метаданих — перевірте special vdev.
Стабілізувати спочатку, оптимізувати потім
- Видалити або замінити несправний компонент (диск, кабель/шлях HBA).
- Тротлити або перенести фонові роботи (реплікації, scrubs, видалення snapshot) з пікових періодів.
- Перевірити заповненість пулу і фрагментацію; плануйте додавання ємності до настання точки болю аллокатора.
- Лише після стабілізації: налаштовуйте властивості датасетів під навантаження (recordsize, compression, atime, sync/logbias де доречно).
План ребалансування (бо додавання vdev не переміщує старі блоки)
- Створіть новий датасет (або новий пул) з правильними властивостями.
- Використайте
zfs send/zfs receiveщоб переписати дані на новий розподіл алокацій. - Перемкніть споживачів (mountpoints, шари, конфігурацію VM).
- Видаліть старі датасети, щоб звільнити простір і зменшити фрагментацію.
Контрольний список проєктування, щоб запобігти дисбалансу (що б я нав’язував у стандарті збірки)
- Гомогенні vdev: однакова модель диска, сімейство прошивки і приблизний рівень зносу.
- Послідовний ashift (встановлюйте свідомо).
- Розділяйте ролі продуктивності тільки з відповідними пристроями (PLP для SLOG, enterprise SSD для special vdev).
- Запас ємності: не експлуатуйте пули при 85–95% заповненості, якщо вам важливі випадкові I/O.
- Санітарність шляхів контролера: перевіряйте expanders/backplanes; тримайте чергування однаковим між vdev.
- Операційна гігієна: регулярні scrubs, моніторинг SMART-трендів і чітка відповідальність за ресурсоємні задачі.
FAQ
1) Чи завжди один повільний диск сповільнює весь пул ZFS?
Не завжди, але часто достатньо, щоб планувати під це. Якщо повільний диск всередині RAIDZ vdev, він може підвищити латентність того vdev.
Якщо ваше навантаження залежить від I/O цього vdev (воно залежатиме) — p99 латентність може зрости. ARC може приховувати проблеми з читанням, поки не втратить ефективність.
2) Чому ZFS «використовує» повільний vdev взагалі?
Тому що пул складається з vdev, і ZFS алокує по них. Він може зміщувати алокації за вільним простором і евристиками,
але не може постійно уникати vdev, не видаливши його. Якщо ви хочете, щоб ZFS не використовував якийсь vdev — потрібно редизайнити: замінити або видалити.
3) Якщо я додам новий швидкий vdev, чи ZFS перерозподілить існуючі дані?
Ні. Існуючі блоки залишаються там, де були. Нові алокації будуть схилятись до vdev з більшим вільним простором, тож продуктивність може покращуватись поступово,
коли робочий набір зміниться. Якщо вам потрібен негайний ребаланс — перепишіть дані (send/recv або міграція).
4) Чи RAIDZ чутливіший до дисбалансу vdev, ніж mirror?
Загалом так для малих випадкових записів і поведінки під час відновлення. RAIDZ має накладні витрати паритету і може робити read-modify-write для часткових смуг.
Mirror може обслуговувати читання з будь-якої сторони, що іноді маскує повільного учасника на читаннях, але записи все одно платитимуть за повільнішого члена.
5) Чи special vdev може стати вузьким місцем, навіть якщо це SSD?
Абсолютно. SSD — не гарантія; це клас пристроїв з широким розкидом характеристик. Малий special vdev може заповнитися, а споживчий SSD може тротлити,
мати стрибки латентності або швидко зношуватись під інтенсивним метаданим і малими блоками. Розглядайте special vdev як tier-0, а не як кеш.
6) Чи варто відключати sync-записи, щоб «поліпшити» продуктивність?
Лише якщо ви готові втратити підтверджені записи при відключенні живлення або падінні процесу, і розумієте, що це означає для вашого додатку.
Для баз даних і VM сховища легковажне встановлення sync=disabled — це деградація надійності, замаскована під виграш у бенчмарку.
7) Наскільки заповнений пул — це вже багато?
Залежить від навантаження, але якщо вам важлива випадкова латентність запису — починайте насторожуватись вище ~70–80% і плануйте ємність до 85%.
У аллокатора менше хороших варіантів при зменшенні вільного простору; фрагментація й метадані підсилюють проблему.
8) Який найшвидший спосіб довести, що проблема — в апаратурі, а не в «тонкому налаштуванні ZFS»?
Комбінуйте: zpool iostat -v показує один vdev з вищим wait, iostat -x показує високий await/%util на конкретних пристроях,
і dmesg/smartctl показують скиди або лічильники помилок. Це трикутник аргументів, з яким важко сперечатися на нараді.
9) Чи неправильний ashift може зробити один vdev повільнішим за інші?
Так, і це незворотно для того vdev. Невідповідність вирівнювання може збільшувати ампліфікацію записів і латентність.
Якщо знайдете vdev з неправильним ashift — плануйте заміну/міграцію. Не витрачайте тижні на налаштування навколо помилки геометрії.
10) Чому пул відчувається повільним, коли активний лише один датасет?
Тому що vdev — спільні ресурси, і ZFS має глобальні операції (txg commits, оновлення метаданих, space map). Галасливий сусід датасет може
наситити vdev, підвищити час очікування і вплинути на інші робочі навантаження. Використовуйте розділення навантажень (різні пули), коли ставки високі.
Висновок: кроки, що дійсно дають результат
ZFS не «таємниче сповільнюється». Він робить саме те, для чого спроєктований: зберігає цілісність, розподіляє по vdev і продовжує працювати,
навіть коли частини системи кульгають. Ціна в тому, що ви відчуваєте кожну повільну ланку там, де це має значення: латентність синхронних записів,
метадані і хвостова поведінка.
Зробіть наступне:
- Знайдіть повільний vdev за допомогою
zpool iostat -vі підтвердіть черезiostat -x. - Перевірте шлях: журнали ядра + SMART-лічильники. Рано замінюйте кабелі і підозрілі диски.
- Аудит special vdev і SLOG. Якщо вони в критичному шляху — будувати їх як продакшен, а не як лабораторію.
- Плануйте ребалансування через переписування після розширень. Додавання vdev дає потенціал; переписування даних його реалізує.
- Тримайте запас. Якщо ви хочете прогнозоване випадкове I/O, припиніть вважати нормальним пул на 90% заповненості.
Якщо запам’ятаєте одну річ: пул такий швидкий, яким є найповільніший vdev саме в момент, коли вашому навантаженню це потрібно.
Не сперечайтеся з цим. Проєктуйте під це, моніторте і замінюйте найслабші ланки, поки вони не представились вашим клієнтам.