Pager спрацьовує через повідомлення «сховище повільне». Графік показує зростання латентності, але тільки час від часу. Команда додатку запевняє, що нічого не змінювала.
Ви заходите на сервер, запускаєте zpool status і бачите: блискучий новий vdev, доданий тиждень тому, стоїть поруч із старішими, заповненішими vdev, ніби новачок,
який отримав усі легкі тікети й якось зламав прод.
ZFS робить додавання місткості дуже простим. Але це також полегшує створення макету пулу, який назавжди буде нерівномірним за продуктивністю й ризиком.
Пастка проста: zpool add додає vdev до пулу, але ZFS не перерозподіляє автоматично існуючі дані між vdev. Старі vdev залишаються заповненими старими блоками;
новий vdev починає порожнім і поглинає багато нових алокацій.
Пастка «Add VDEV»: що відбувається насправді
Коли ви виконуєте zpool add, ви не «додаєте диски» до існуючої групи надмірності. Ви додаєте новий топ-рівневий vdev до пулу. ZFS потім розподіляє нові записи
по топ-рівневих vdev, орієнтуючись на вільне місце й кілька евристик, але він не переміщує старі блоки.
Старі vdev залишаються заповненими старими даними; новий vdev починає порожнім і поглинає більшість нових алокацій.
Це здається прийнятним, поки ви не згадаєте, що означає топ-рівневий vdev: IOPS, пропускна здатність і стійкість пулу — це сума (або мінімум)
властивостей його топ-рівневих vdev. Додайте vdev із іншою шириною, іншим класом дисків, іншим ashift або іншим профілем здоров’я — і ви змінюєте
поведінку пулу на все майбутнє.
Один пул — багато особливостей
Пули ZFS — це не «одна RAID-група». Пул — це збірка топ-рівневих vdev. Кожен топ-рівневий vdev має власну надмірність (mirror, RAIDZ, dRAID),
а пул стріпує між ними. Це потужна модель. Водночас саме так люди випадково створюють сторожу з кількох непоєднуваних частин:
три широкі RAIDZ2 vdev, потім одне mirror «щоб швидко додати ємність», потім спеціальний SSD vdev «для метаданих», і тепер пул
поводиться як комітет, де кожен голосує, а найповільніший все одно затримує зустріч.
Чому ZFS не робить ребаланс автоматично
Відсутність авто-ребалансування — це не лінощі; це консервативність. Переміщати блоки в активному пулі дорого, зношує накопичувачі, створює ризик у кутах від втрати живлення
і ускладнює гарантії. ZFS охоче зберігає вказівники на місце, де дані вже лежать. Він оптимізований на коректність і життєздатність, а не на «зробити гарно».
Операційний висновок простий: якщо ви додали vdev і потім дивуєтеся, чому один vdev робить всю роботу — відповідь: «бо він порожній і на нього пишуть нові дані».
Якщо ви дивуєтеся, чому читання все ще б’є по старим vdev — це тому, що старі дані там і залишилися. ZFS не діє містично.
Він діє буквально.
Факти та контекст, що пояснюють поведінку
- ZFS починався в Sun на початку 2000-х, і був спроєктований для наскрізної цілісності даних із контрольними сумами на кожному блоці, а не тільки «швидкої RAID».
- Пули були радикальною зміною: замість зрізання LUN з фіксованих RAID-груп ви агрегуєте vdev і алокуєте динамічно.
- Copy-on-write — основний механізм: ZFS ніколи не перезаписує живі блоки на місці; він записує нові блоки й змінює вказівники. Це чудово для снапшотів, але ускладнює «ребаланс».
- Топ-рівневі vdev — одиниця відмови: втрата топ-рівневого vdev означає втрату пулу. Саме тому одиночний диск як топ-рівневий vdev — це тикаюча бомба.
- RAIDZ не те саме, що RAID5/6 в реалізації; це розрядна смуга з парністю, яка взаємодіє з recordsize і патернами алокацій так, що дивує людей з апаратних RAID.
- Ashift залишається назавжди на vdev: виберіть неправильне вирівнювання секторів — і ви можете зафіксувати write amplification на весь термін служби цього vdev.
- Спеціальні vdev (metadata/small blocks) зробили гібридні пули практичнішими, але вони також додали компонент, втрата якого може «спалити» пул, якщо він не віддзеркалений.
- L2ARC ніколи не був write-кешем: це read-кеш і він скидається при перезавантаженні, якщо не ввімкнено та не підтримується персистентний L2ARC. Люди все ще ставляться до нього як до магічної RAM.
- Resilver веде себе по-різному для різних vdev: у зеркалах resilver працює за використаним простором; у RAIDZ resilver важчий і зачіпає більше геометрії vdev.
Чому нерівномірність шкодить: продуктивність, надійність і вартість
Продуктивність: пул такий гладкий, як його найповільніший vdev
У збалансованому пулі IOPS і пропускна здатність масштабуються при додаванні топ-рівневих vdev подібних можливостей. У нерівномірному пулі виникає дивна поведінка:
сплески гарної продуктивності, а потім стрибки латентності, коли один vdev насичений, а інші недовантажені.
Класичний сценарій: ви додаєте новий vdev, нові записи в основному йдуть туди, моніторинг виглядає відмінно. Потім навантаження зміщується на читання старих даних
(відновлення бекапів, аналітика по історичних партиціях або флот віртуальних машин, що завантажується зі старих образів). Раптом старі vdev стають «гарячими» для читань,
а новий vdev просто стоїть без діла.
Надійність: змішування рівнів надмірності — це купівля ризику за CAPEX
Відмовостійкість пулу — це не «середня надмірність». Це надмірність кожного топ-рівневого vdev, і втрата будь-якого з них вбиває пул.
Додайте один mirror поруч із кількома RAIDZ2, і ви щойно ввели слабку ланку: дводискове mirror витримає одну відмову диска,
тоді як ваш RAIDZ2 — дві. Тепер домени відмов нерівномірні.
Додайте одиночний диск як «тимчасово», і вітаємо: ви створили пул, що знаходиться в одній відмові диска від повної втрати.
Слово «тимчасово» має довгий період напіврозпаду в інфраструктурі.
Вартість: ви платите двічі — за диски і за наслідки
Нерівномірні пули дорожчі в нудних аспектах: більше on-call часу, більше ескалацій, більше розборок «чому цей хост повільніший», більше передчасних оновлень.
І якщо вам доведеться «виправляти» макет, виправлення часто руйнівне: міграція даних, перебудова пулів або контрольоване перезаписування блоків, що може зайняти тижні.
Жарт №1: Додавати несумісний vdev до пулу ZFS — це як поставити запасне колесо на гоночний автомобіль — так, воно котиться, і так, усі чують його.
Швидкий план діагностики (перші/другі/треті перевірки)
Коли хтось каже «ZFS повільніший після додавання дисків», не починайте з налаштування recordsize. Почніть з доведення, чи пул нерівномірний і куди йдуть ресурси.
Перше: чи один топ-рівневий vdev виконує всю роботу?
- Перевірте I/O та латентність по vdev за допомогою
zpool iostat -v. - Шукайте один vdev з постійно вищим busy/await, ніж інші.
- Якщо бачите це — зупиніться. Ви не налагоджуєте «продуктивність ZFS», ви налагоджуєте «макет і алокацію».
Друге: це завантаження читаннями, записами чи синхронними записами?
- Мікс читання/запису:
zpool iostat -v 1іarcstat(якщо доступно) для показників ARC і тиску на читання. - Синхронні записи: перевірте
zfs get syncі наявність та стан SLOG. - Якщо піки латентності корелюють із сплесками sync-записів, ви дивитесь на ZIL/SLOG або на латентність запису на рівні диска.
Третє: чи справді ви блокуєтесь на шарі пристрою?
- Перевірте статистику пристроїв ядра:
iostat -xі лічильники помилокsmartctl. - Підтвердіть ashift і розміри секторів. Новий vdev з іншим фізичним розміром сектора може поводитись інакше під навантаженням.
- Шукайте тихі неприємності: контролер знизив швидкість лінії, диск у режимі SATA 1.5G або NCQ вимкнено.
Практичні завдання (команди, виводи, рішення)
Нижче — реальні завдання, які можна виконати на типовому хості Linux з OpenZFS. Кожне містить, що означає вивід і яке рішення прийняти.
Використовуйте їх як чекліст, коли ви позбавлені сну й вікно змін закінчується.
Завдання 1: Показати топологію пулу і одразу помітити «новий vdev»
cr0x@server:~$ sudo zpool status -v tank
pool: tank
state: ONLINE
scan: scrub repaired 0B in 03:12:44 with 0 errors on Tue Dec 10 02:40:11 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 0 0 0
sdj ONLINE 0 0 0
sdk ONLINE 0 0 0
sdl ONLINE 0 0 0
mirror-2 ONLINE 0 0 0
nvme0n1p2 ONLINE 0 0 0
nvme1n1p2 ONLINE 0 0 0
errors: No known data errors
Значення: Цей пул має два RAIDZ2 vdev і потім mirror. Той mirror — інший клас (NVMe) і інший профіль надмірності.
Рішення: Ставтеся до цього як до гетерогенного пулу. Очікуйте перекосу алокацій і «режимів» продуктивності. Якщо цей mirror додали заради ємності, плануйте міграцію
або розумний підхід до ребалансування, а не додаткові латки.
Завдання 2: Визначити, який vdev «гарячий» (IOPS і пропускна здатність)
cr0x@server:~$ sudo zpool iostat -v tank 1 5
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank 82.1T 21.9T 3.21K 1.05K 410M 198M
raidz2-0 41.0T 3.7T 2.80K 190 360M 31M
sda - - 470 32 61M 5.2M
sdb - - 458 30 59M 5.1M
sdc - - 472 31 61M 5.1M
sdd - - 469 33 60M 5.3M
sde - - 467 31 60M 5.2M
sdf - - 464 33 59M 5.2M
raidz2-1 40.9T 3.8T 380 175 49M 29M
sdg - - 64 29 8.1M 4.8M
sdh - - 63 30 8.0M 4.9M
sdi - - 62 28 8.0M 4.7M
sdj - - 64 29 8.2M 4.8M
sdk - - 63 29 8.0M 4.8M
sdl - - 64 30 8.1M 4.9M
mirror-2 250G 850G 30 690 1.2M 138M
nvme0n1p2 - - 15 345 0.6M 69M
nvme1n1p2 - - 15 345 0.6M 69M
-------------------------- ----- ----- ----- ----- ----- -----
Значення: Читання домінують на raidz2-0. Записи домінують на NVMe mirror. Це класична поведінка «новий vdev поглинає записи»
і «старі vdev обслуговують читання».
Рішення: Якщо скарги на латентність пов’язані з читаннями, додавання додаткових vdev під записи не виправить їх. Потрібно перемістити гарячі дані,
додати подібні RAIDZ vdev або переглянути дизайн пулу.
Завдання 3: Підтвердити перекіс алокацій і наскільки він серйозний
cr0x@server:~$ sudo zpool list -v tank
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 104T 82.1T 21.9T - - 28% 78% 1.00x ONLINE -
raidz2-0 45.5T 41.0T 3.7T - - 34% 91% - ONLINE
raidz2-1 45.5T 40.9T 3.8T - - 31% 90% - ONLINE
mirror-2 1.09T 250G 850G - - 2% 22% - ONLINE
Значення: Два великі vdev заповнені приблизно на 90%, новий mirror — близько 22% заповнення. Це не «збалансована ємність», отже й навантаження не буде збалансованим,
якщо тільки ваше навантаження дивним чином не складається лише з нових записів.
Рішення: Не додавайте крихітні vdev в надії, що ZFS «розподілить все». Вирішіть, чи додавати більше vdev тієї ж конфігурації/ширини,
чи мігрувати в новий пул із чистим макетом.
Завдання 4: Перевірити ashift і виявити проблему «новий vdev інший»
cr0x@server:~$ sudo zdb -C tank | sed -n '1,120p'
MOS Configuration:
version: 5000
name: 'tank'
state: 0
txg: 1293387
pool_guid: 14772854026870511222
vdev_children: 3
vdev_tree:
type: 'root'
id: 0
guid: 14772854026870511222
children[0]:
type: 'raidz'
ashift: 12
nparity: 2
children[0]: type: 'disk' path: '/dev/sda'
...
children[2]:
type: 'mirror'
ashift: 13
children[0]: type: 'disk' path: '/dev/nvme0n1p2'
children[1]: type: 'disk' path: '/dev/nvme1n1p2'
Значення: RAIDZ vdev мають ashift=12 (4K). Mirror має ashift=13 (8K). Це не обов’язково помилка, але це постійна відмінність у поведінці.
Рішення: Якщо ви бачите випадкові mismatches ashift через некоректне визначення секторів або змішані типи пристроїв, не продовжуйте додавати латки.
Плануйте перебудову з правильним ashift, а не насипайте ще невідповідностей.
Завдання 5: Перевірити властивості датасету, що змінюють латентність (sync, recordsize, compression)
cr0x@server:~$ sudo zfs get -r compression,recordsize,sync tank/vmstore
NAME PROPERTY VALUE SOURCE
tank/vmstore compression lz4 local
tank/vmstore recordsize 16K local
tank/vmstore sync standard default
Значення: Розумні VM-налаштування: стиснення lz4 і recordsize 16K. Sync — standard, тобто синхронні записи дотримуються.
Рішення: Якщо ви бачите латентність синхронних записів і у вас немає SLOG, розгляньте додавання дзеркального SLOG на пристроях із захистом від втрати живлення.
Не «виправляйте» latency sync шляхом sync=disabled, якщо не готові потім пояснювати втрату даних у постмортемі.
Завдання 6: Перевірити, чи існує 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
raidz2-1 ONLINE 0 0 0
mirror-2 ONLINE 0 0 0
logs
mirror-3 ONLINE 0 0 0
nvme2n1p1 ONLINE 0 0 0
nvme3n1p1 ONLINE 0 0 0
Значення: Є дзеркальний лог-пристрій. Добре: немає одно- приладного SLOG. Також він відокремлений від топ-рівневого mirror.
Рішення: Якщо логи показані як одиночний диск — виправте це перш ніж робити інші зміни. Одиночний SLOG — це очікувана точка відмови,
а повільний SLOG — фабрика латентності для sync-важких навантажень.
Завдання 7: Виміряти реальну латентність і черги на рівні ОС
cr0x@server:~$ iostat -x 1 3
Linux 6.8.0 (server) 12/25/2025 _x86_64_ (32 CPU)
Device r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 78.0 5.0 62.1 4.1 173.2 9.80 110.2 120.3 18.1 2.8 23.1
sdg 12.0 4.0 9.5 3.2 194.0 0.90 22.4 24.1 17.3 2.4 3.8
nvme0n1 1.0 420.0 0.2 132.0 64.0 1.10 2.6 1.9 2.6 0.1 4.2
Значення: sda має високий await і чергу в порівнянні з іншими дисками. Зазвичай це означає, що vdev, якому він належить, насичений.
Рішення: Підтвердіть, що це відповідає zpool iostat -v. Якщо так — у вас «гарячий» vdev.
Якщо ні — можливо проблеми з контролером або шляхом до конкретного диска.
Завдання 8: Перевірити тиск на ARC і чи пропускаються читання з кешу
cr0x@server:~$ sudo arcstat 1 3
time read miss miss% dmis dm% pmis pm% mmis mm% size c
12:01:11 3200 1200 37 800 25 350 11 50 2 118G 128G
12:01:12 3400 1500 44 980 29 420 12 60 2 118G 128G
12:01:13 3350 1480 44 950 28 430 13 60 2 118G 128G
Значення: Рівень пропуску кешу близько 40%+ під навантаженням. Це може перетворити історію «швидкий новий vdev» на «читання по старих vdev нас вбивають»,
бо ARC не рятує.
Рішення: Якщо пропуски читань корелюють із латентністю, розгляньте додавання RAM (часто найкращий апгрейд IOPS за долар),
або винесення гарячих датасетів на швидші, правильно сконфігуровані vdev замість змішування.
Завдання 9: Перевірити фрагментацію і розпізнати «обрив майже повного RAIDZ vdev»
cr0x@server:~$ sudo zpool get -H -o property,value fragmentation tank
fragmentation 28%
Значення: Фрагментація немаленька. У RAIDZ висока заповненість + фрагментація може підсилювати вартість запису й варіативність латентності.
Рішення: Якщо ваші RAIDZ vdev заповнені на 85–90% і фрагментація зростає, припиніть «тонке налаштування». Додавайте еквівалентні vdev або мігруйте.
Фізика алокації переможе.
Завдання 10: Подивитися, чи якийсь датасет домінує (і перемістити його при потребі)
cr0x@server:~$ sudo zfs list -o name,used,available,refer,compressratio -r tank | head -n 12
NAME USED AVAIL REFER RATIO
tank 82.1T 21.9T 128K 1.22x
tank/vmstore 42.8T 21.9T 42.8T 1.05x
tank/backups 25.6T 21.9T 24.1T 1.48x
tank/analytics 11.9T 21.9T 10.7T 1.31x
tank/home 1.8T 21.9T 1.8T 1.63x
Значення: VMstore домінує за простором. Якщо саме він створює гаряче навантаження, то він же домінує по I/O.
Рішення: Розгляньте переміщення tank/vmstore у новий, правильно спроєктований пул і залиште холодніші датасети на старому.
Хірургічний поділ краще, ніж героїчне «ребалансування всього».
Завдання 11: Перевірити приховані помилки пристроїв перед тим, як звинувачувати алокацію
cr0x@server:~$ sudo smartctl -a /dev/sda | egrep "Reallocated_Sector_Ct|Current_Pending_Sector|Offline_Uncorrectable|UDMA_CRC_Error_Count"
Reallocated_Sector_Ct 0
Current_Pending_Sector 0
Offline_Uncorrectable 0
UDMA_CRC_Error_Count 27
Значення: CRC-помилки вказують на проблеми з кабелем/бекплейном/контролером, а не на помираючі медіа. Це може проявлятися як «один vdev повільний».
Рішення: Виправте фізичний шлях і зупиніть тренд помилок (замініть кабель, перепідключіть, переставте в іншу шухляду) перед тим, як перекроювати пул.
Завдання 12: Підтвердити, що «новий vdev» дійсно використовується для нових алокацій
cr0x@server:~$ sudo zpool iostat -v tank 5
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank 82.1T 21.9T 980 2.20K 210M 420M
raidz2-0 41.0T 3.7T 820 180 180M 40M
raidz2-1 40.9T 3.8T 150 160 28M 36M
mirror-2 250G 850G 10 1.86K 2.0M 344M
-------------------------- ----- ----- ----- ----- ----- -----
Значення: Записи йдуть переважно на mirror vdev. Це очікувано, коли він вільніший і швидший.
Рішення: Якщо цей mirror не мав стати основним сходом для записів (через вартість, витривалість або політику),
потрібно перекроїти архітектуру, а не «сподіватися, що воно вирівняється».
Завдання 13: Довести, що ви не зможете пізніше видалити топ-рівневий vdev (це незворотно)
cr0x@server:~$ sudo zpool remove tank mirror-2
cannot remove mirror-2: operation not supported on this pool
Значення: Видалення топ-рівневого vdev може не підтримуватись залежно від вашої версії OpenZFS і фіч-флагів пулу — а навіть коли підтримується,
це обмежено і може зайняти багато часу.
Рішення: Ставтеся до zpool add як до постійної операції, якщо ви не перевірили підтримку видалення vdev у вашому середовищі
і готові терпіти час та ризики.
Завдання 14: Перевірити конфігурацію special vdev (бо його втрата може втратити пул)
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
raidz2-0 ONLINE 0 0 0
raidz2-1 ONLINE 0 0 0
special
mirror-4 ONLINE 0 0 0
nvme4n1p1 ONLINE 0 0 0
nvme5n1p1 ONLINE 0 0 0
Значення: Special vdev віддзеркалений. Добре. Якби він був одиночним пристроєм і помер — ви могли б втратити метадані/малі блоки і фактично втратити пул.
Рішення: Ніколи не тримайте special vdev як одиночний пристрій у продакшені. Дзеркальте його, моніторьте і залишайте запас потужності.
Три міні-історії з реальних кейсів
Міні-історія 1: Інцидент через хибне припущення
Середня SaaS-компанія мала пул ZFS для віртуалізаційного кластера. Було дві RAIDZ2 vdev однакових HDD. Зростання було рівномірним.
Потім з’явився новий клієнт і сховище різко підросло. Хтось поставив очевидне питання: «Чи можемо просто додати диски?»
Інженер на чергуванні зробив те, що багато з нас зробили б о 2-й ночі: додав новий mirror vdev із двома запасними дисками, бо було швидко і терміново потрібна ємність.
Він припустив, що пул «перерозподілить», або принаймні «вирівняє I/O» з часом. Пул залишився онлайн, графіки покращилися, і всі повернулися спати.
Через два тижні команда платформи викотила новий образ VM і флот перезавантажився. Boot storm — це читання з великою кількістю малих випадкових I/O.
Читання били по старих даних на майже повних RAIDZ vdev. Латентність злетіла. Новий mirror мав багато вільного місця й швидкість, але це не допомогло, бо він містив переважно нові блоки.
Аварія не була таємницею; це був борг по топології, що нарахував відсотки. Їхнє рішення не було тонким налаштуванням. Вони перемістили найгарячіші VM-датасети в новий пул,
збудований із mirrors (під навантаження), а старий пул перепрофілювали під холодніші дані. Болючий урок: ZFS не захистить вас від власних припущень.
Міні-історія 2: Оптимізація, що повернулася бумерангом
Команда аналітики хотіла швидших запитів. У них був пул ZFS із RAIDZ2 HDD vdev. З’явилася пропозиція: «Додайте пару NVMe у mirror vdev, і ZFS буде стріпувати туди. Бум: швидше».
Вони додали NVMe mirror як топ-рівневий vdev. Нові записи (включно з тимчасовими spill-файлами запитів) лягли непропорційно на NVMe. Спочатку все виглядало фантастично.
Але NVMe були споживчі й не мали гарантії безпечного вимкнення. Гірше: вони опинилися на шляху гарячих записів для навантаження, яке робило багато синхронних операцій
через поведінку додатку, яку вони не до кінця контролювали.
Через кілька місяців один NVMe почав давати помилки медіа. Mirror захистив від негайної втрати даних, але продуктивність сильно впала під час обробки помилок
і ресилвера. Вплив на бізнес був: «запити іноді тривають в 10 разів довше», що для аналітики означає не повний простій, а фактично непрацездатність.
Наслідок був тонким: вони не просто «додали продуктивність». Вони змінили алокацію, характеристики відмов і операційну поведінку всього пулу.
Їхнє остаточне рішення було прозаїчним: перемістити scratch-аналітику в окремий NVMe-пул (mirrors), залишити HDD-пул для довговічних даних і явізно встановити sync-семантику.
Міні-історія 3: Нудна, але правильна практика, що врятувала
Фінансова компанія використовувала ZFS для архіву документів і VM-ферми. Їхній керівник зберігання мав алергію на «швидкі латки» і наполягав на політиці:
топ-рівневі vdev мають бути ідентичні за шириною, типом і класом дисків; виключення — тільки за письмовим погодженням ризику.
Політика дратувала людей, бо робила розширення повільнішим. Коли ємності бракувало, вони не «додавали що є під руками».
Вони купували достатньо дисків, щоб додати повноцінний новий RAIDZ2 vdev, що відповідав існуючим, і виконували staged change із burn-in тестами.
Через місяці у них виникла проблема з прошивкою контролера, що періодично підвищувала латентність на одному SAS-шляху. Оскільки vdev були однорідні,
метрики чітко вказували: один шлях поводиться неправильно; макет пулу не замилював сигнал. Вони ізолювали проблемний шлях, коректно переключилися та запланували прошивку.
Порятунок не був героїчним; він був у ясності. Однорідні vdev і дисципліновані зміни зробили систему передбачуваною, коли апарат почав поводитися дивно,
а саме тоді ви справді дізнаєтесь, з чого зроблена ваша архітектура.
Як безпечно розширювати ZFS (що робити натомість)
Правило 1: Додавайте топ-рівневі vdev однакові, або прийміть постійну дивність
Якщо ви збираєтеся зростати пул шляхом додавання vdev, додавайте vdev того ж типу, тієї ж ширини і подібного класу продуктивності. Mirrors до mirrors.
RAIDZ2 до RAIDZ2 з тією ж кількістю дисків. Подібний ashift. Подібні моделі дисків, коли можливо.
Це не естетика. Це операційна математика: пул стріпує між vdev, і будь-який vdev може стати обмежуючим фактором залежно від патернів доступу.
Однорідність робить планування продуктивності і ємності передбачуваним.
Правило 2: Якщо потрібні різні типи медіа — використовуйте окремі пули або special vdev свідомо
Хочете NVMe для затримки і HDD для ємності? Є три розумні підходи:
- Окремі пули: один NVMe-пул для latency-чутливих датасетів, один HDD-пул для масиву. Просто, передбачувано, легко пояснити.
- Special vdev (дзеркальний): для метаданих і малих блоків, щоб прискорити операції з директоріями і випадкові малі I/O, залишаючи дані на HDD.
- SLOG (дзеркальний, PLP-пристрої): щоб знизити латентність синхронних записів без зміни місця кінцевого зберігання даних.
Чого слід уникати — це «просто додати швидкий vdev» і сподіватися, що ZFS перетворить його на систему tiering. Не перетворить. Він перетворить його на стік алокації.
Правило 3: Розгляньте перебудову замість латання, коли макет уже зіпсовано
Іноді правильна відповідь: збудувати новий пул із потрібним макетом, а потім мігрувати датасети. Так, це робота. Але це кінцева робота.
Життя з компромісним пулом — це нескінченна робота.
А що з «ребалансом»?
ZFS не має однокомандного онлайн-ребалансування, яке б перерасподіляло існуючі блоки між vdev як у деяких розподілених системах.
Якщо ви хочете перемістити дані, зазвичай доводиться їх перезаписувати.
Практичні підходи включають:
- send/receive датасету в новий пул (кращий варіант, якщо ви можете виділити новий пул).
- Перезапис датасету на місці через реплікацію у тимчасовий датасет і назад (працює, але важке та ризиковане в експлуатації).
- Селективна міграція гарячих датасетів у новий пул, залишаючи холодні дані як є.
Жарт №2: ZFS не «ребалансить» ваш пул; він «зберігає історію». Як ваш аудит-відділ, пам’ятає все і нічого не рухає без паперів.
Контрольні списки / покроковий план
Покроково: перед тим, як виконати zpool add у продакшені
- Запишіть ціль: ємність, IOPS, пропускна здатність чи латентність? «Більше місця» — це не план продуктивності.
- Підтвердіть геометрію vdev: mirror vs raidz, кількість дисків, ashift, класи пристроїв.
- Вирішіть, чи зможете зберегти однорідність vdev: якщо ні, вирішіть, чи приймаєте постійну гетерогенність.
- Перевірте вільний простір і фрагментацію: якщо ви вже високо заповнені, очікуйте гіршого поведінки при записах.
- Валідуйте контролер і шляхи: не додавайте складності поверх хиткої апаратури.
- Заплануйте відкат: прикиньте, що ви не зможете видалити vdev — як ви мігруватимете, якщо щось піде не так.
- Підготуйте і прогрійте диски: запустіть тривалі SMART-тести, перевірте прошивку, підтвердіть розміри секторів.
Покроково: безпечні шаблони розширення
- Потрібна ємність у існуючому RAIDZ: додайте новий RAIDZ vdev, що відповідає ширині і парності існуючих.
- Потрібні IOPS для VM-подібних випадків: додавайте mirror vdev (кілька mirrors добре масштабують IOPS).
- Потрібна швидка латентність синхронних записів: додайте дзеркальний SLOG на пристроях із захистом від втрати живлення; не додавайте випадковий швидкий топ-рівневий vdev.
- Потрібне прискорення метаданих/малих блоків: додайте дзеркальний special vdev; налаштовуйте
special_small_blocksлише з моделлю розрахунку розміру та моніторингом. - Потрібні обидва рівні: збудуйте два пули і явно розміщуйте датасети.
Покроково: якщо ви вже впали в пастку
- Квантифікуйте нерівномірність: відсоток алокації по vdev,
zpool iostatпід реальним навантаженням. - Визначте гарячі датасети: які датасети домінують у I/O і спричиняють скарги на латентність.
- Оберіть цільову архітектуру: однорідні vdev або окремі пули під навантаження.
- Сплануйте міграцію: send/receive з інкрементальними снапшотами або перемістіть спочатку гарячі датасети.
- Заплануйте scrubs і resilver: розширення й міграції — коли слабкі диски виявляються.
Типові помилки: симптом → корінь → виправлення
1) Симптом: «Після додавання дисків читання все ще повільні»
Корінь: Ви додали новий vdev, але старі дані залишилися на старих vdev; читальне навантаження все ще б’є по старим, переповненим vdev.
Виправлення: Перемістіть гарячі датасети в новий пул або перезапишіть їх, щоб блоки перерозподілилися. Якщо ви мусите розширювати на місці,
додавайте відповідні vdev, щоб збільшити паралелізм читань там, де лежать дані.
2) Симптом: «Записи стали швидкими, а потім з’явилися випадкові стрибки латентності»
Корінь: Новий vdev бере більшість записів; старі vdev наближаються до повноти і фрагментовані; змішані типи медіа створюють нерівномірний час обслуговування.
Виправлення: Перестаньте змішувати топ-рівневі класи vdev для загальної алокації. Розділіть пули або використайте SLOG/special vdev для цільового прискорення.
3) Симптом: «Продуктивність пулу непослідовна по хостах / часах доби»
Корінь: Фази навантаження (читання старих даних проти записів нових даних) взаємодіють із перекосом алокацій. Пул має «режими».
Виправлення: Вимірюйте I/O по vdev під кожну фазу навантаження. Розміщуйте датасети за патернами доступу, а не виходячи з того, де був вільний простір.
4) Симптом: «Час scrub або resilver вибухнув після розширення»
Корінь: Висока заповненість vdev + геометрія RAIDZ + повільні диски = довгі операції обслуговування. Розширення не зменшило заповненість старих vdev.
Виправлення: Додавайте відповідні vdev до того, як досягнете високого CAP%. Тримайте запас ємності. Проактивно замінюйте старі диски. Розгляньте mirrors для швидшого resilver, якщо навантаження вимагає.
5) Симптом: «Ми додали одиночний диск тимчасово і тепер боїмося торкатися пулу»
Корінь: Один диск як топ-рівневий vdev робить пул уразливим: один збій — і все втрачене.
Виправлення: Негайно перетворіть цей одиночний диск у надмірний (прикріпіть другий диск у mirror) або мігруйте дані з цього пулу.
Не відкладайте це «на потім».
6) Симптом: «Новий vdev швидший, але пул у цілому став повільнішим»
Корінь: Змішаний ashift, розміри секторів або write amplification на одному vdev; плюс метадані/малі блоки можуть концентруватися на певних пристроях.
Виправлення: Перевірте ashift і властивості пристроїв перед додаванням. Якщо помилка — перебудуйте з правильним ashift; не додавайте більше невідповідностей.
7) Симптом: «Синхронні записи жахливі, тож хтось пропонує sync=disabled»
Корінь: Немає SLOG або він повільний/небезпечний. Пул дотримується sync-семантики і платить латентністю.
Виправлення: Додайте дзеркальний SLOG на пристроях з захистом від втрати живлення; підтвердіть потреби додатку; зберігайте sync=standard заради цілісності, якщо ви не готові ризикувати втратою даних.
Часті запитання після інциденту
1) Чи «додавати диски» те ж саме, що «додати vdev» у ZFS?
Практично так. Ви або замінюєте диски в існуючому vdev (зростаючи його або оновлюючи), або додаєте новий топ-рівневий vdev до пулу.
zpool add додає новий топ-рівневий vdev. Це змінює поведінку пулу назавжди.
2) Чи ZFS автоматично перерозподіляє дані після додавання vdev?
Ні. Існуючі блоки лишаються на своїх місцях. Нові алокації віддають перевагу vdev з більшим вільним простором, тому нові vdev часто отримують більшість нових записів.
3) Якщо я додаю швидший vdev, чи стануть читання швидшими?
Лише для даних, які розміщені на тому vdev (або кешуються в ARC/L2ARC). Якщо ваші гарячі дані живуть на старих vdev, читання все одно звертатимуться до них.
4) Чи можна «виправити нерівномірність» без міграції в новий пул?
Іноді частково можна — перезаписавши дані (send/receive у тимчасовий датасет і назад або переміщення датасетів).
Але безкоштовного обіду немає: щоб перемістити блоки, їх треба перезаписати, і це важко по I/O і по часу.
5) Чи безпечно змішувати mirrors і RAIDZ vdev в одному пулі?
Це може бути безпечно в сенсі функціонування ZFS, але рідко розумно з погляду передбачуваної продуктивності або послідовних характеристик відмов.
Якщо ви так робите — робіть це свідомо і моніторьте поведінку по vdev. В іншому випадку розділіть пули.
6) Який найпоширеніший «ми випадково зламали це» рух при розширенні ZFS?
Додавання маленького mirror vdev до великого RAIDZ-пулу, бо «трохи місця не завадить». В результаті пул виділяє алокації непропорційно на mirror,
змінює схему зносу і ускладнює майбутнє планування ємності.
7) Чи додавання більшої кількості vdev завжди підвищує продуктивність?
Додавання більше подібних топ-рівневих vdev зазвичай збільшує агрегований throughput і IOPS. Додавання різнорідних vdev збільшує непередбачуваність.
Також якщо ваше навантаження обмежене CPU, ARC, sync-семантикою або мережею — більше vdev не допоможуть.
8) Як обрати між mirrors і RAIDZ для росту?
Mirrors краще масштабують випадкові read/write IOPS і швидше resilver; RAIDZ ефективніший по ємності, але більше чутливий до заповненості і патернів запису.
Для VM або баз даних із великою кількістю випадкових I/O mirrors зазвичай більш передбачувані в експлуатації.
9) Яка цитата, що варто пам’ятати, коли хтось хоче «швидко полагодити сховище»?
Вернер Фогельс (парафраз): «Все відмовляє, весь час». Будуйте макети й процедури, припускаючи, що наступна відмова вже запланована.
Висновок: наступні кроки на цей тиждень
Якщо ви запам’ятаєте одне, то нехай це буде: zpool add не «розширює RAID». Він додає новий топ-рівневий vdev і не перерозподіляє старі дані.
Це не баг. Це модель.
Практичні наступні кроки:
- Перевірте інвентар пулів: запустіть
zpool statusі запишіть типи vdev, ширину та класи пристроїв. Якщо там безлад — визнайте це зараз. - Зміряйте навантаження по vdev: зафіксуйте
zpool iostat -v 1під час реальних піків навантаження. Знайдіть гарячий vdev. - Прийміть рішення про архітектуру: однорідні vdev в одному пулі або кілька пулів за навантаженням. Не продовжуйте імпровізувати.
- Сплануйте вихід: якщо ви вже додали невідповідний vdev, заплануйте шлях міграції, поки система ще здорова для перенесення даних.
Надійність сховища — це в основному уникання хитростей. ZFS дає вам гострі інструменти. Використовуйте їх так, ніби ви будете тим, хто на чергуванні, коли все піде не так.