Найгірший тип проблем зі зберіганням — це та, що «зазвичай працює». Віртуальна машина завантажується. База даних проходить початкові тести.
А потім хтось запускає реальне навантаження в 10:14 у вівторок, і ваш графік латентності iSCSI перетворюється на сучасне мистецтво.
Симптом — заїдання: періодичні паузи, довгі хвости латентності, і користувачі описують це як «повільно», ніби це показник.
Якщо ви експортуєте ZFS ZVOL через iSCSI, ви тримаєте ланцюг гострих ножів: транзакційні групи ZFS, синхронна семантика,
черги iSCSI, multipath і кешування в гостьовій ОС. Помилитися в геометрії — і ви проведете тиждень, звинувачуючи «мережу»,
поки ZFS чемно чекатиме, поки ваш маленький SLOG не почне плавитися.
Ментальна модель: звідки береться затримання
«Затримання» під навантаженням рідко пов’язані з грубою пропускною здатністю. Це варіативність. Медіана I/O виглядає нормально, але 99.9-й перцентиль
стає нестерпним: гість зупиняється, контрольна точка бази даних уповільнюється, гіпервізор панікує й повторює спроби, а команда застосунків подає тікет
з назвою «Сховище випадково зависає».
При експорті ZFS ZVOL через iSCSI затримання зазвичай походить від одного з цих вузьких місць:
- Обробка синхронних записів: клієнт відправляє запис з FUA/flush семантикою; ZFS має безпечно зафіксувати дані. Без належного SLOG латентність стрибає.
- Поводження транзакційної групи (TXG): ZFS групує записи і періодично синхронізує їх. Неправильно задані ліміти брудних даних або повільний пул можуть роздути час sync TXG.
- Несумісність розміру блоків: клієнт робить 4K випадкові записи, а ваш ZVOL має volblocksize 128K — це примушує read-modify-write і ампліфікує I/O.
- Черги та зворотний тиск: глибина черги ініціатора iSCSI, чергування на таргеті та черги vdev у ZFS можуть створювати «зубчасту» латентність.
- Витягнуті тайм-лаги фізичного шару: один збійний SSD, проблемний HBA, або флапання шляху в multipath. ZFS підкаже вам проблему, якщо ви задасте правильні питання.
Практична мета: передбачувана латентність під тривалим навантаженням, навіть якщо пікова пропускна здатність трохи впаде.
У продакшні нудна і стабільна робота перемагає.
Цікаві факти та контекст (щоб ви не повторювали помилки)
- ZFS народився в Sun у середині 2000-х як комплексний стек зберігання: контрольні суми, пулове зберігання, снапшоти та copy-on-write. Це не просто «файлова система поверх RAID» — скоріше «зберігання, що відмовляється брехати».
- Copy-on-write робить снапшоти дешевими, але також означає, що перезаписи стають новими записами, і фрагментація має значення. Блокові навантаження з великою кількістю випадкових перезаписів можуть «старити» пул швидше, ніж ви очікуєте.
-
ZVOL — це не файл. ZVOL — блоковий пристрій, підкріплений ZFS. Ця відмінність важлива: ZVOL не має
recordsize; він маєvolblocksize, і його важче змінити пізніше. - iSCSI походить з 1990-х як «SCSI поверх TCP». Він переміг, бо Ethernet переміг, а не через свою чарівність. Саме тому «продуктивність сховища» може залежати від дрібних TCP-особливостей.
- ZFS Intent Log (ZIL) існує, щоб зробити синхронні записи надійними. Окремий лог-пристрій (SLOG) — не кеш записів; це низьколатентна точка для збереження намірів синхронних записів.
- Ранні рекомендації ZFS формувалися під вінчестери і великі послідовні записи. Сучасні SSD/NVMe зрушили вузьке місце від часу переміщення головки до ампліфікації латентності та поведінки черг.
- 4K сектори змінили гру (Advanced Format). Якщо ви неправильно виставите ashift, можна випадково перетворити 4K запис у read-modify-write на рівні диска. Це податок, який ви платите назавжди.
- Раніше стиснення лякали на блокових навантаженнях. Сучасний LZ4 достатньо швидкий, щоб увімкнення стиснення часто зменшувало I/O і покращувало латентність, особливо для образів VM і баз даних з повторюваними шаблонами.
- Multipath спочатку був про відмовостійкість, але тепер також про продуктивність. Помилкова конфігурація може змусити вас балансувати навантаження в пакетну втрату і тайм-аути.
Проєктні рішення, що важливі (і ті, що ні)
Виберіть ZVOL чи dataset зі свідомим підходом
Якщо клієнт очікує блочний пристрій (хост для гіпервізора, том Windows, кластерна база даних, що хоче «сирі» диски), використовуйте ZVOL.
Якщо можна піднести файли (NFS, SMB) і ви контролюєте I/O-патерни додатка, dataset зазвичай простіше налаштувати й спостерігати.
Але ця стаття про ZVOL, тож залишимося на цьому полі бою.
Volblocksize: рішення «форматування», яке важко змінити
volblocksize — внутрішній розмір блоку, який ZFS використовує для ZVOL. Він сильно впливає на ампліфікацію записів і метадані.
Менші блоки краще підходять для випадкових I/O. Великі блоки зменшують накладні витрати для послідовних навантажень, але карають за дрібні випадкові записи.
- Системні/завантажувальні диски VM: 8K або 16K — безпечний старт. 8K часто лідирує для змішаних випадкових читань/записів. 16K може знизити накладні витрати, якщо навантаження не надто «балакуче».
- Бази даних (OLTP-подібні): 8K, якщо сторінка БД — 8K (часто). Підлаштуйтеся під реальність. Не сперечайтеся з фізикою.
- Великі послідовні дані (цільові бекапи, медіа): 64K–128K можуть бути доречними, але не експортуйте це як загальний datastore для VM, якщо вам не подобаються таємничі паузи.
Змінити volblocksize можна лише через пересоздання ZVOL і міграцію даних. Це не вихідних робіт на вихідні, якщо ви вже в продакшні.
Ashift: вирішуйте один раз і терпіть наслідки
ashift — показник розміру сектору пулу в степенях двійки (наприклад, 12 означає 2^12 = 4096 байт). Якщо ваші фізичні пристрої 4K (а вони такими є), встановіть ashift=12.
Для багатьох SSD 12 правильний; для деяких 8K-пристроїв може бути 13.
Головне: не дозволяйте «auto-detect» помилитися й виявляти це після того, як у пулі вже є дані.
Синхронні записи: розумійте, що клієнт просить гарантувати
Синхронні записи — це та частина, де система зберігання обіцяє, що дані не зникнуть при відключенні живлення.
По iSCSI гості й файлові системи частіше виконують flush-и і FUA, ніж здається — особливо в віртуалізованих стеках.
ZFS може обробляти синхронні записи без SLOG, записуючи їх у основний пул, але латентність буде залежати від найповільнішого vdev у пулі.
Якщо вам важливий хвостовий латентність, ймовірно, варто мати виділений SLOG на низьколатентних PLP SSD/NVMe.
SLOG: не «більше кешу», а «менше очікування»
SLOG пришвидшує підтвердження синхронних записів, швидко фіксуючи намір. Пізніше ZFS скидає транзакційну групу на основний пул.
Якщо у вас інтенсивні sync-навантаження, SLOG повинен мати:
- Низьку латентність під тривалими записами (не лише «швидкий послідовний» режим).
- Захист від втрати живлення (PLP), інакше ви можете втратити підтверджені sync-записи.
- Достатню витривалість для вашої швидкості записів (ZIL-записи можуть бути агресивними).
Жарт #1: Купувати «геймерський NVMe» для SLOG — це як найняти спринтера як нічного сторожа — швидкий, так, але спить під час відключення живлення.
Стиснення: увімкніть, якщо немає сильної причини не робити цього
Використовуйте compression=lz4 для більшості ZVOL-навантажень. Навіть якщо дані мало стиснуться, накладні витрати невеликі на сучасних CPU.
Виграш часто в тому, що менше байтів потрапляє на диск і менше I/O, що може знизити латентність.
Dedup: не вмикайте
Dedup на ZVOL — класична функція «виглядала гарно на слайді». Вона збільшує навантаження на пам’ять і може посилити латентність.
Якщо ви не моделювали, не бенчмаркували і не можете дозволити собі RAM та операційну складність, не вмикайте.
Спеціальні vdev і метадані: корисно, але легко зловживати
Спеціальні пристрої для алокації можуть пришвидшити метадані й малі блоки.
На системах з великою кількістю ZVOL це може допомогти, але це також відкрита область для надійності.
Якщо ви втратите спеціальний vdev із метаданими, можна втратити пул, якщо він не налаштований в дзеркалі.
Ставтеся до нього як до основного сховища, а не як до «бонусного SSD».
Мережа: 10/25/40/100GbE не вирішує проблему латентності
iSCSI чутливий до втрат пакетів, натискання буферів і нестабільності шляхів. Швидке з’єднання з мікроударими все одно може фризити.
Ваша мета — стабільна латентність, а не просто великі числа в iperf.
Побудова ZVOL iSCSI-таргета, що залишається плавним
Базові припущення
Приклади припускають Linux-сервер з ZFS (OpenZFS), що експортує блочні LUN через iSCSI за допомогою LIO (targetcli).
Клієнт — ініціатор Linux, але ми відзначимо Windows/ESXi підводні камені.
Підлаштовуйте під вашу платформу, але дотримуйтеся принципів: вирівнюйте геометрію, поважайте sync і вимірюйте латентність там, де вона виникає.
Розташування пулу: дзеркала краще за RAIDZ для латентності випадкових записів
Для VM/iSCSI блокових навантажень дзеркала зазвичай краще за RAIDZ по латентності і передбачуваності IOPS. RAIDZ може бути прийнятним для переважно послідовних
або читально-насичених навантажень, але малі випадкові записи торкаються парності і можуть посилити латентність під час відбудови.
Якщо ви змушені використовувати RAIDZ заради ємності, закладайте гірші очікування для синхронних записів і більш виражені хвости під час scrub/resilver.
Ви все ще можете працювати в продакшні; просто не дивуйтеся потім.
Створіть ZVOL з розумними властивостями
Хороший стартовий набір для загального ZVOL-диска під VM:
volblocksize=8Kабо16Kзалежно від навантаженняcompression=lz4sync=standard(не встановлюйтеdisabledщоб «вирішити» латентність, якщо вам не подобається втрата даних)logbias=latencyдля sync-насичених навантажень (часто для VM)
Також вирішіть, чи потрібне тонке виділення. ZVOL можуть бути thin або thick. Thin зручний. Thin також дозволяє людям
переприсвоюватися, поки пул не досягне 100% і все не перетвориться на повільний інцидент.
Експортуйте його через iSCSI з передбачуваним чергуванням
З LIO зазвичай ви:
- Створюєте backstore, що вказує на ZVOL
- Створюєте iSCSI target IQN і портал
- Створюєте LUN-мапінг і ACL
- При потребі налаштовуєте сесії, відновлення помилок і таймаути
Де ховається затримання: надмірна кількість невиконаних I/O може створити враження «періодичного зависання», коли черга спорожняється.
Недотюніння може обмежити пропускну здатність, але надмірне тюнінгування викликає сплески хвостової латентності й таймаути. Вам потрібна достатня глибина черги, щоб диски були зайняті,
а не настільки, щоб створити I/O-пробку.
Multipath на стороні клієнта: нудно, специфічно та обов’язково для продакшну
Multipath вирішує дві проблеми: відмовостійкість і розподіл навантаження. Він також створює новий режим відмови: path flapping, коли клієнт
«стрибає» між шляхами і ваше сховище здається таким, що «втратить пакети», хоча насправді воно піддається політиці йо-йо.
Використовуйте два фізично окремі шляхи, якщо стверджуєте про резервування. Окремі NIC, окремі комутатори, по можливості окремі шляхи. Інакше — театральність.
Одна цитата, яка справді належить у опс
«Надія — не стратегія.» — парафразована думка, часто приписувана операторам і інженерам у роботі з надійністю
Практичні завдання: команди, результати та рішення
Ви не можете налаштовувати те, що не спостерігаєте. Нижче — практичні завдання, які можна виконати на ZFS/iSCSI таргеті та ініціаторі.
Кожне завдання містить: команду, що типовий вивід означає, і яке рішення з цього випливає.
Завдання 1: Перевірте стан пулу та очевидні апаратні помилки
cr0x@server:~$ sudo zpool status -v tank
pool: tank
state: ONLINE
scan: scrub repaired 0B in 0 days 02:11:43 with 0 errors on Sun Dec 22 03:10:16 2025
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
mirror-1 ONLINE 0 0 0
nvme2n1 ONLINE 0 0 0
nvme3n1 ONLINE 0 0 0
errors: No known data errors
Значення: будь-які ненульові READ/WRITE/CKSUM помилки — це підказка, а не пропозиція. Навіть один ненадійний пристрій може створити «затримання»
через повтори та повільне завершення I/O.
Рішення: якщо бачите помилки або деградований vdev, припиніть тюнінг. Виправте апаратні проблеми перш ніж щось налаштовувати. Робота над продуктивністю на пошкодженому сховищі — просто інсценування.
Завдання 2: Підтвердіть ashift і топологію vdev (від тут починаються очікування латентності)
cr0x@server:~$ sudo zdb -C tank | egrep -i 'ashift|vdev_tree|type'
type: 'root'
type: 'mirror'
ashift: 12
type: 'mirror'
ashift: 12
Значення: ashift=12 означає вирівнювання під 4K. Якщо ви знайдете ashift=9/10/11 на 4K-пристроях, ви знайшли постійний «податок».
Рішення: неправильний ashift зазвичай означає «перебудувати пул правильно». Якщо це неможливо негайно, документуйте ризик і не обіцяйте низької латентності.
Завдання 3: Перевірте заповненість пулу (ZFS сердиться, коли тісно)
cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint tank
NAME USED AVAIL REFER MOUNTPOINT
tank 18.2T 2.11T 256K /tank
Значення: при ~10% вільного простору фрагментація та поведінка алокатора можуть підвищити варіативність латентності, особливо на блокових навантаженнях.
Рішення: прагніть мати значний вільний простір (часто 20%+ для завантажених пулів). Якщо тісно — плануйте ємність перш ніж налаштовувати глибини черги.
Завдання 4: Перевірте властивості ZVOL (розмір блоку, стиснення, sync)
cr0x@server:~$ zfs get -o name,property,value -s local,default volblocksize,compression,sync,logbias,refreservation tank/zvol/vmstore
NAME PROPERTY VALUE
tank/zvol/vmstore volblocksize 8K
tank/zvol/vmstore compression lz4
tank/zvol/vmstore sync standard
tank/zvol/vmstore logbias latency
Значення: це ваш базовий «чеклист на адекватність». sync=disabled на VM datastore — червоний прапор, якщо ви не прийняли явного ризику.
Рішення: якщо volblocksize явно не підходить для навантаження (наприклад, 128K для OLTP), плануйте міграцію на новий ZVOL. Це не вирішується шляхом sysctl.
Завдання 5: Створіть ZVOL правильно (приклад) і поясніть, чому
cr0x@server:~$ sudo zfs create -V 4T -b 8K -o compression=lz4 -o logbias=latency -o sync=standard tank/zvol/vmstore2
Значення: -V створює блочний том, -b задає volblocksize при створенні, і ми явно обираємо поведінку, дружню до latency при sync-записах.
Рішення: вибирайте 8K, коли не знаєте краще і очікуєте випадкові записи. Вибирайте 16K якщо навантаження змішане, але не надто дрібне, і ви хочете трохи меншого метаданого накладного навантаження.
Завдання 6: Переконайтесь, що блочний пристрій існує і подивіться розміри секторів
cr0x@server:~$ ls -l /dev/zvol/tank/zvol/vmstore2
lrwxrwxrwx 1 root root 13 Dec 25 10:12 /dev/zvol/tank/zvol/vmstore2 -> ../../zd16
cr0x@server:~$ sudo blockdev --getss /dev/zd16
4096
cr0x@server:~$ sudo blockdev --getpbsz /dev/zd16
4096
Значення: ZVOL тут представляє 4K логічні сектори. Зазвичай це добре для сучасних гістьових систем і вирівнюється з ashift=12.
Рішення: якщо ваш ініціатор/ОС очікує 512, а ви подаєте 4K, деякі старі гостьові системи поводяться погано. Для сучасних систем 4K зазвичай краще.
Завдання 7: Перевірте, чи є виділений SLOG і чи він у дзеркалі
cr0x@server:~$ sudo zpool status tank | sed -n '1,120p'
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
mirror-1 ONLINE 0 0 0
nvme2n1 ONLINE 0 0 0
nvme3n1 ONLINE 0 0 0
logs
mirror-2 ONLINE 0 0 0
nvme4n1 ONLINE 0 0 0
nvme5n1 ONLINE 0 0 0
Значення: дзеркальний SLOG знижує ризик того, що відмова одного лог-пристрою призведе до втрати останніх синхронних записів (залежно від сценарію відмови).
Рішення: якщо ви працюєте з sync-насиченим iSCSI і вам важлива коректність, використовуйте дзеркальний SLOG з PLP. Якщо не можете — прийміть вищу латентність синхронних записів і налаштуйте очікування.
Завдання 8: Дивіться латентність ZFS і чергування в реальному часі
cr0x@server:~$ sudo zpool iostat -v tank 1
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 18.2T 2.11T 820 1900 91.3M 76.2M
mirror - - 410 950 45.6M 38.1M
nvme0n1 - - 205 470 22.8M 19.3M
nvme1n1 - - 205 480 22.8M 18.8M
mirror - - 410 950 45.7M 38.1M
nvme2n1 - - 205 475 22.9M 19.1M
nvme3n1 - - 205 475 22.8M 19.0M
logs - - 0 600 0 12.0M
mirror - - 0 600 0 12.0M
nvme4n1 - - 0 300 0 6.0M
nvme5n1 - - 0 300 0 6.0M
Значення: ви можете бачити, чи записи йдуть на лог-пристрій (sync-насичене навантаження), і чи якийсь vdev відстає.
Рішення: якщо один пристрій стабільно показує менше ops чи bandwidth у дзеркалі, підозрівайте латентність пристрою, прошивку, термальне дроселювання або проблеми PCIe-топології.
Завдання 9: Перевірте поведінку TXG і підказки «кадусу» стуттеру
cr0x@server:~$ sudo arcstat.py 1 5
time read miss miss% dmis dm% pmis pm% mmis mm% arcsz c
10:20:01 920 80 8 0 0% 40 50% 40 50% 128G 128G
10:20:02 980 70 7 0 0% 35 50% 35 50% 128G 128G
10:20:03 910 95 10 0 0% 47 49% 48 51% 128G 128G
10:20:04 940 82 9 0 0% 41 50% 41 50% 128G 128G
10:20:05 960 78 8 0 0% 39 50% 39 50% 128G 128G
Значення: тиск на ARC і пропуски часто корелюють із латентністю читань, а не записів. Але якщо ваш «стуттер» насправді викликаний хвилею cache miss-ів,
це покаже: високі miss% у момент пауз додатку.
Рішення: якщо ARC заповнений і miss% високий, розгляньте пам’ять, робочу множину або переносіть читально-важкі навантаження на файлові протоколи, де кешування ефективніше.
Не поспішайте додавати L2ARC без вимірів.
Завдання 10: Підтвердіть конфігурацію iSCSI-таргета і змеплені LUNи
cr0x@server:~$ sudo targetcli ls
o- / ............................................................................. [...]
o- backstores ................................................................. [...]
| o- block ............................................................. [Storage Objects: 1]
| | o- vmstore2 ........................................ [/dev/zvol/tank/zvol/vmstore2 (4.0TiB)]
o- iscsi ............................................................... [Targets: 1]
o- iqn.2025-12.lab:storage.tank ............................................. [TPGs: 1]
o- tpg1 .......................................................... [no-gen-acls, no-auth]
o- acls ............................................................... [ACLs: 1]
| o- iqn.2025-12.lab:client01 .............................................. [Mapped LUNs: 1]
o- luns ............................................................... [LUNs: 1]
| o- lun0 ............................... [block/vmstore2 (/dev/zvol/tank/zvol/vmstore2)]
o- portals ......................................................... [Portals: 1]
o- 10.0.10.10:3260 .............................................................. [OK]
Значення: перевірте, що backstore вказує на потрібний ZVOL і що ACL мапить правильний IQN ініціатора.
Рішення: якщо виявите fileio backstore для високопродуктивного VM-сховища, перегляньте рішення: block backstore до ZVOL зазвичай чистіший і швидший варіант.
Завдання 11: На ініціаторі підтвердіть сесії і погоджені параметри
cr0x@server:~$ sudo iscsiadm -m session -P 3 | sed -n '1,120p'
iSCSI Transport Class version 2.0-870
iscsiadm version 2.1.9
Target: iqn.2025-12.lab:storage.tank
Current Portal: 10.0.10.10:3260,1
Persistent Portal: 10.0.10.10:3260,1
DataDigest: None
HeaderDigest: None
MaxRecvDataSegmentLength: 262144
MaxXmitDataSegmentLength: 262144
FirstBurstLength: 262144
MaxBurstLength: 1048576
InitialR2T: No
ImmediateData: Yes
Значення: ці параметри впливають на продуктивність і завантаження CPU. Дигести додають навантаження на CPU, але допомагають виявити корупцію на поганих мережах.
Більшість чистих дата-центрів працюють без digest.
Рішення: якщо CPU — вузьке місце або ви бачите повтори пакетів, перегляньте мережу і MTU перш за все. Не «тюньте» iSCSI bursts як перший крок; рідко саме це головна проблема.
Завдання 12: Перевірте стан multipath (flap-шляхи створюють «стуттер»)
cr0x@server:~$ sudo multipath -ll
mpatha (36001405f3f2b7f8d9d5b3d2a8c1e0001) dm-3 IET,VIRTUAL-DISK
size=4.0T features='1 queue_if_no_path' hwhandler='0' wp=rw
|-+- policy='service-time 0' prio=50 status=active
| `- 4:0:0:0 sdb 8:16 active ready running
`-+- policy='service-time 0' prio=50 status=enabled
`- 5:0:0:0 sdc 8:32 active ready running
Значення: ви хочете стабільні шляхи «active ready running». Якщо бачите, що шляхи переключаються між failed/active, отже це джерело ваших сплесків латентності.
Рішення: виправте кабелі/комутатори/NIC/MTU перш ніж чіпати ZFS-налаштування. Тюнінг сховища не може перебити фізику і втрати пакетів.
Завдання 13: Перевірте TCP-повторні передачі та дропи NIC на таргеті
cr0x@server:~$ sudo nstat -az | egrep 'TcpRetransSegs|TcpExtTCPRenoReorder|IpInDiscards'
TcpRetransSegs 12 0.0
IpInDiscards 0 0.0
Значення: повторні передачі додають варіативності латентності. Невелика кількість за тривалий час — нормально; швидке зростання під навантаженням — ні.
Рішення: якщо повтори зростають під час «стуттера», розслідуйте буфери комутатора/ECN, невідповідний MTU, погану оптику/кабелі або насичення IRQ/CPU на NIC.
Завдання 14: Спостерігайте латентність дисків прямо (не гадіть)
cr0x@server:~$ sudo iostat -x 1 3
Linux 6.8.0 (server) 12/25/2025 _x86_64_ (32 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
12.10 0.00 5.20 2.80 0.00 79.90
Device r/s w/s rkB/s wkB/s rrqm/s wrqm/s %util await r_await w_await
nvme0n1 210.0 480.0 24000 20000 0.0 0.0 71.0 1.80 1.20 2.10
nvme1n1 215.0 470.0 24500 19800 0.0 0.0 69.0 1.90 1.30 2.20
nvme2n1 205.0 475.0 23500 19900 0.0 0.0 73.0 1.70 1.10 2.00
nvme3n1 205.0 475.0 23600 20100 0.0 0.0 72.0 1.75 1.15 2.05
Значення: якщо await підстрибує до десятків/сотень мілісекунд під час стуттеру, ваші пристрої пулу — вузьке місце (або змушені чекати sync).
Рішення: якщо латентність пристроїв нормальна, але клієнт бачить стуттер, підозрівайте чергування iSCSI, flapping multipath або поведінку sync-записів (SLOG, флеш-шторм).
Завдання 15: Ідентифікуйте тиск на синхронні записи (підказки використання ZIL/SLOG)
cr0x@server:~$ sudo zfs get -o name,property,value sync,logbias tank/zvol/vmstore2
NAME PROPERTY VALUE
tank/zvol/vmstore2 sync standard
tank/zvol/vmstore2 logbias latency
cr0x@server:~$ sudo zpool iostat -v tank 1 | sed -n '1,20p'
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 18.2T 2.11T 200 2400 22.0M 98.0M
logs - - 0 1200 0 24.0M
Значення: значні операції запису в logs вказують на sync-активність (ZIL). Якщо у вас немає SLOG, ці sync-записи йдуть на основні vdev і можуть викликати сплески латентності.
Рішення: якщо ваше навантаження sync-важке і ви чутливі до латентності, впровадьте належний SLOG. Якщо він вже є, але стуттер лишається, перевірте, чи не виснажений він або чи не дроселюється термічно.
Завдання 16: Запустіть контрольний fio-тест з ініціатора (виміряйте потрібну річ)
cr0x@server:~$ sudo fio --name=iscsi-4k-randwrite --filename=/dev/mapper/mpatha --direct=1 --rw=randwrite --bs=4k --iodepth=32 --numjobs=4 --time_based=1 --runtime=60 --group_reporting
iscsi-4k-randwrite: (groupid=0, jobs=4): err= 0: pid=4121: Thu Dec 25 10:30:12 2025
write: IOPS=18.2k, BW=71.2MiB/s (74.7MB/s)(4272MiB/60001msec)
slat (usec): min=4, max=1120, avg=15.2, stdev=9.8
clat (usec): min=90, max=84210, avg=650.1, stdev=2100.4
lat (usec): min=110, max=84230, avg=666.2, stdev=2101.0
clat percentiles (usec):
| 1.00th=[ 140], 10.00th=[ 180], 50.00th=[ 310], 90.00th=[ 980], 99.00th=[ 5800]
| 99.90th=[38000], 99.99th=[79000]
Значення: середня латентність виглядає нормально, але 99.90-й на 38мс і 99.99-й на 79мс — це ваш «стуттер». Саме це відчувають користувачі.
Рішення: оптимізуйте хвостову латентність, а не середню. Якщо хвости періодично стрибають, корелюйте з часами sync TXG, поведінкою SLOG і мережевими повторними передаваннями.
Швидкий план діагностики
Коли з’являється стуттер, потрібен короткий список дій, що швидко звузить радіус пошуку. Ось порядок, який я використовую, бо він знаходить
«очевидно поламаний» клас проблем до того, як ви витратите години на тюнінг.
По-перше: виключіть відмови і флапи
- zpool status: є помилки пристроїв, деградовані vdev або resilver? Якщо так — це і є історія.
- multipath -ll на ініціаторах: чи є шляхи, що відмовляють/флапають? Якщо так — виправте мережу/шляхи.
- nstat / лічильники NIC: повтори, дропи, переповнення кілець. Якщо так — у вас проблема з мережею/CPU IRQ.
По-друге: вирішіть, чи це латентність дисків, чи синхронна семантика
- iostat -x на таргеті: чи стрибки await? Якщо так — диски або SLOG повільні чи насичені.
- zpool iostat -v 1: чи показують лог-пристрої інтенсивні записи? Якщо так — ви sync-насичені; якість SLOG має значення.
- fio percentiles: висока хвостова латентність при помірній середній часто вказує на періодичні flush/sync або події спорожнення черги.
По-третє: шукайте невідповідності конфігурації і ампліфікацію
- volblocksize: не відповідає навантаженню? 128K ZVOL для 4K випадкових записів вичавить систему під тиском.
- заповненість пулу: майже повні пули посилюють проблеми алокатора і фрагментацію.
- RAIDZ + малі випадкові sync-записи: очікуйте вищі хвости, особливо під час scrub/resilver.
По-четверте: тонко налаштуйте глибину черги
Тюнінг глибини черги — останній крок, бо він може маскувати проблеми або створити нові. Але після перевірки здоров’я системи,
регулювання глибини ініціатора і політик multipath може згладити латентність без компромісу коректності.
Поширені помилки: симптом → корінь → виправлення
-
Симптом: періодичні сплески латентності кожні кілька секунд під навантаженням запису
Корінь: тиск TXG sync + повільне стабільне записування, часто відсутній або поганий SLOG
Виправлення: додати дзеркальний PLP SLOG; перевірити, що лог-записи потрапляють на нього; переконатися, що пул не майже заповнений; планувати scrub/resilver не в пікові години. -
Симптом: хороша пропускна здатність, але «зависання» у VM, особливо Windows-гостей
Корінь: флеш-штормі (guest filesystem, гіпервізор або додаток), синхронна латентність записів, видима через iSCSI
Виправлення: правильний SLOG, триматиsync=standard; розглянути тонке налаштування кеш-політики на гості (тільки після оцінки ризиків). -
Симптом: жахливі IOPS при 4K випадкових записах, висока завантаженість дисків, дивно низька пропускна здатність
Корінь: volblocksize занадто великий, що викликає read-modify-write ампліфікацію
Виправлення: створити новий ZVOL з volblocksize 8K/16K і перемістити дані; не намагайтеся «виправити» це налаштуваннями. -
Симптом: стуттер з’являється тільки з увімкненим multipath
Корінь: нестабільний вторинний шлях, надто агресивний path checker, помилкова конфігурація комутатора, асиметрична маршрутизація
Виправлення: стабілізувати L2/L3 спочатку; встановити розумні політики multipath; уникати «round-robin для всього», якщо ваш таргет або мережа не можуть це чисто обслуговувати. -
Симптом: латентність погіршується після увімкнення L2ARC
Корінь: L2ARC краде RAM/CPU, трясе кеш або SSD конкурує з робочим навантаженням пулу
Виправлення: видалити L2ARC; збільшити RAM; додавати L2ARC тільки після вимірювання робочої множини читань і після виділення швидкого пристрою. -
Симптом: продуктивність падає під час scrub/resilver
Корінь: розмітка пулу (RAIDZ), обмежений запас IOPS, scrub конкурує з продакшеном, дисбаланс vdev
Виправлення: планувати scrub; при потребі тюнити поведінку scrub; проектувати пули з запасом; використовувати дзеркала для latency-критичних блокових навантажень. -
Симптом: «випадкові» паузи; логи показують iSCSI таймаути/перепідключення
Корінь: TCP повторні передачі, несумісний MTU, проблемні NIC offload-и, насичення CPU IRQ
Виправлення: перевірити MTU наскрізь; перевірити дропи; прив’язати IRQ; розглянути вимкнення проблемних offload-ів; тримати конфіг простим і вимірюваним. -
Симптом: використання простору виглядає нормальним, але раптом все сповільнюється при досягненні ємності
Корінь: тонке виділення і переприсвоєння + пул досяг високого завантаження
Виправлення: застосувати quotas/refreservation; ранні алерти; тримати вільний простір; трактувати ємність як SLO, а не як таблицю в електронній таблиці.
Три корпоративні історії з практики
Міні-історія 1: Інцидент через хибне припущення (volblocksize «не має значення»)
Середня компанія мігрувала з застарілого Fibre Channel SAN на ZFS‑базований iSCSI таргет. План тестування був «скопіювати кілька VM,
прогнати тест входу, вважати за добре». У лабораторії все виглядало нормально. У продакшні ERP-система почала «зависати» на кілька секунд
під час пікового навантаження.
Інфраструктурна команда припустила, що мережа перевантажена, бо iSCSI «на TCP», а TCP «трошки крихкий». Вони додали пропускну здатність:
оновили uplink-и, перебудували VLAN, навіть замінили комутатор. Затримання залишилося, чемно не змінене. Користувачі й далі казали:
«він трохи припиняється, а потім наздоганяє».
Підказка була в сфокусованому fio-прогоні, що відтворив проблему: 4K випадкові записи показали великі хвости латентності, хоча середня латентність
була прийнятною. На боці ZFS ZVOL створили з volblocksize 128K — бо хтось прочитав блог «більші блоки — швидше».
Для ERP навантаження I/O були малі, випадкові і sync-важкі.
Під навантаженням ZFS робив read-modify-write цикли по великих блоках для дрібних оновлень, переробляючи метадані й примушуючи додаткові I/O.
Система не була «повільною», радше «спорадично нестерпною». Виправлення було непоказне: створити новий ZVOL з volblocksize 8K,
мігрувати LUN на рівні гіпервізора і тримати compression увімкненим.
Мережеве оновлення не пропало даремно — воно покращило запас потужності, але не вплинуло на корінь проблеми. Постмортем змінив процес побудови:
розмір блоку став формальним проєктним параметром, а не дефолтом.
Міні-історія 2: Оптимізація, що повернулася бумерангом (sync=disabled «для швидкості»)
Інше середовище запускало віртуалізаційний кластер на ZFS iSCSI. У них був пристойний пул, мережа й усе ж скарги на паузи VM
під час вікон патчування. Хтось виявив, що sync=disabled робить бенчмарки блискучими. Вони застосували це до основного VM ZVOL
під час технічного вікна і оголосили перемогу.
Деякий час все виглядало чудово. Графіки латентності згладилися. Служба підтримки замовкла. Потім подія з відключенням живлення вдарила по одному стояку — не по всьому дата-центру,
а по одному PDU. Сервер сховища перезавантажився. Декілька VM повернулись із пошкодженими файловими системами.
Не всі. Але достатньо, щоб інцидент був реальним і розлюченим.
Оптимізація команди не була тюнінгом. Це була зміна цілісності. З sync=disabled система підтверджувала записи, що залишалися в леткій кеш-пам’яті.
Для деяких VM це не мало значення; для інших — катастрофічно. Відновлення було міксом відкату з бекапів, ремонту файлових систем і одного довгого вікенду пояснень керівництву.
Довгострокове виправлення — не нотація, а архітектура: дзеркальний PLP SLOG для sync-навантажень і відмова від зміни семантики збереження даних заради приємніших графіків.
Вони також додали тести, що імітують втрату живлення шляхом примусового жорсткого перезавантаження під синхронними навантаженнями у пре-продакшні.
Жарт #2: sync=disabled — це еквівалент зняття пожежних датчиків, бо вони надокучливо пищать.
Міні-історія 3: Нудна, але правильна практика, що врятувала день (запас ємності + дисципліна scrub)
Фінансова компанія використовувала ZFS iSCSI для dev/test і частини продакшн-аналітики. Їхній lead зі сховища мав одну вперту політику:
тримати пули нижче порогу використання, і запускати scrubs за графіком з чіткими алертами на будь-яку checksum-помилку.
Це було нудно. Але це також означало, що вони регулярно сперечалися з менеджерами про запити на ємність. Але вони тримали запас, і ставили
scrub як «неопціональну гігієну», а не «те, що робимо коли нам нудно».
Одного кварталу пакетна робота почала навантажувати сховище випадковими записами і несподіваними sync-flush. Латентність зросла, але не стала катастрофою.
У пулі ще був вільний простір, алокатор не був у пастці, і дзеркала мали запас IOPS. Команда могла загальмувати пакетну роботу,
підкоригувати графіки і тюнити глибину черги ініціатора без екзистенційного тиску.
Під час того ж періоду scrub виявив ранні checksum-помилки на одному пристрої. Його замінили профілактично. Жодного даунтайму, жодної драми, жодної «втраченої половини дня».
Політика не зробила їх героями. Вона зробила систему передбачуваною, а це краще.
Контрольні списки / план покроково
Крок за кроком: побудова нового ZFS iSCSI ZVOL, що не буде стутерити
- Виберіть розмітку пулу для латентності: дзеркала для VM/iSCSI, якщо немає сильної причини інакше.
-
Підтвердіть ashift перед створенням даних: перевірте через
zdb -C. Якщо неправильно, виправте зараз, не пізніше. - Вирішіть volblocksize відповідно до навантаження: 8K/16K для загального VM store; зіставте з DB page size, коли відомо.
- Створіть ZVOL з явними властивостями: compression lz4, sync standard, logbias latency якщо sync-насичене.
- Сплануйте вільний простір: операційна ціль (наприклад, 20% вільного). Налаштуйте алерти раніше, ніж досягнете болю.
- Додайте належний SLOG, якщо sync-важливо: дзеркальний, PLP, низька латентність, витривалість відповідна навантаженню.
- Експортуйте через iSCSI зі стабільною конфігурацією: block backstore до ZVOL; явні ACL; послідовна конфігурація порталів.
- Налаштуйте multipath на ініціаторах: перевірте, що обидва шляхи справді незалежні; підтвердіть стабільний статус «active ready running».
- Запустіть fio percentiles з ініціаторів: вимірюйте хвости, не лише середнє; тестуйте і sync-подібні (fsync) і async патерни.
- Зафіксуйте базову лінію: zpool iostat, iostat -x, retransmits, percentiles латентності. Це стане вашим «відомим добрим» станом.
Операційний чеклист: при додаванні нових LUNів або нових орендарів
- Підтвердіть поріг вільного простору пулу та прогнозований ріст.
- Перевірте, чи
volblocksizeвідповідає очікуваному I/O-профілю орендаря. - Вирішіть, чи використовувати
refreservation, щоб запобігти сюрпризам тонкого виділення. - Перевірте стан і зношення SLOG (поза межами простих ZFS-команд, але обов’язково).
- Заплануйте scrubs і моніторинг checksum-помилок як ключовий сигнал.
- Запустіть короткий fio smoke test після змін у мережі або політиках multipath.
FAQ
1) Чи варто використовувати dataset (файл) через NFS замість ZVOL iSCSI?
Якщо ваш гіпервізор і навантаження задоволені NFS і ви хочете простіший тюнінг та спостережуваність, NFS datasets часто легші.
Використовуйте ZVOL iSCSI, коли потрібні блочні семантики або ОС вимагає їх.
2) Який volblocksize обрати для VM-стору?
Почніть з 8K для загальних VM-навантажень, коли вам важлива латентність випадкових записів. Використовуйте 16K, якщо виміри показують, що навантаження має більші I/O і ви хочете трохи менше метаданого накладного.
Уникайте 64K/128K для змішаних VM store, якщо не маєте справжніх послідовних патернів.
3) Чи можна змінити volblocksize пізніше?
Не in-place. Зазвичай створюють новий ZVOL з бажаним volblocksize і мігрують дані на рівні клієнта/гіпервізора.
Плануйте це заздалегідь.
4) Чи потрібен SLOG для iSCSI?
Якщо ваше навантаження робить sync-записи (багато так роблять) і вам важлива стабільність латентності, так — належний дзеркальний PLP SLOG часто є різницею
між «плавно» і «таємничими паузами». Якщо навантаження переважно async і ви можете терпіти sync-латентність, можливо, можна обійтись без.
5) Чому не просто поставити sync=disabled і насолоджуватись швидкістю?
Бо це міняє коректність. Ви можете втратити підтверджені записи при втраті живлення або краху, і відмова може бути частковою і болючою.
Якщо ви погоджуєтеся на такий ризик для scratch-середовища — задокументуйте це. Для продакшну — не робіть цього.
6) Чи допомагає L2ARC з продуктивністю iSCSI ZVOL?
Іноді, для читально-важких навантажень з робочою множиною більшу за RAM. Але L2ARC споживає RAM і CPU і може конкурувати з пристроями.
Виміряйте ARC hit rate і реальну латентність читань перед додаванням. Це не магічна кнопка «більше кешу».
7) Дзеркала vs RAIDZ для iSCSI: яка практична різниця?
Дзеркала зазвичай дають кращу латентність випадкових записів і передбачувані IOPS під відновленням/скануванням. RAIDZ жертвує цим заради ефективності ємності.
Для VM/БД по iSCSI дзеркала — безпечніший вибір за замовчуванням.
8) Моя мережа 25/100GbE — чому все одно стуттер?
Бо пропускна здатність не лікує хвостову латентність. Мікроудари, повторні передачі, flapping шляхів і насичення CPU можуть викликати паузи навіть на швидких лінках.
Перевірте дропи/повтори і стабільність multipath перш за все.
9) Чи варто вмикати стиснення на ZVOL?
Так, зазвичай lz4. Воно часто зменшує фізичні I/O і покращує латентність. Є винятки (вже стиснені потоки), але «вимкнути за замовчуванням» — стара забобонність.
10) Чому бенчмарки показують нормально, але додатки все ж паузять?
Багато бенчмарків показують середні значення і ховають хвостову латентність. Користувачі відчувають 99.9-й перцентиль. Використовуйте fio percentiles і корелюйте з TXG ZFS,
активністю SLOG і мережевими повторними передачами.
Висновок: наступні кроки, які ви можете зробити цього тижня
Якщо ваш ZFS iSCSI ZVOL стутерить під навантаженням, зазвичай це не одна магічна кнопка. Це ланцюг: геометрія розміру блоків, синхронна семантика, якість лог-пристрою,
чергування і стабільність мережі. Ваше завдання — знайти, де створюються очікування, і прибрати найгірші з них, не обманюючи цілісність даних.
Практичні наступні кроки:
- Прогрійте швидкий план діагностики під час події стуттеру і зафіксуйте докази:
zpool status,zpool iostat -v 1,iostat -x 1, лічильники повторних передач та fio percentiles. - Аудитуйте
volblocksizeкожного ZVOL і визначте аутлайєри, що не відповідають реальному навантаженню. - Явно вирішіть, чи потрібен вам SLOG. Якщо потрібен — купуйте правильний клас пристрою (PLP, низька латентність, дзеркальний), а не «швидкий споживчий NVMe».
- Переконайтесь у стабільності multipath наскрізь. Усуньте flapping шляхів, перш ніж чіпати тюнінг сховища.
- Встановіть політику ємності й алерти, щоб тримати пул поза зоною «майже повний», де стуттер стає стилем життя.