ZFS-пули: чому «мислення через розділи» шкодить вашому дизайну

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

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

ZFS — це не менеджер розділів із підключеною файловою системою. ZFS — це система зберігання, яка хоче володіти своїми пристроями від початку до кінця: топологія, надмірність, семантика запису, відновлення і продуктивність. Коли ви проєктуєте її як купу розділів, ви не просто робите її безладною — ви робите її крихкою, повільнішою та складнішою для відновлення, коли щось піде не так (а так буде, у вівторок, за п’ять хвилин до замороження змін).

Що таке «мислення через розділи» (і чому воно так привабливе)

«Мислення через розділи» — це звичка ставитися до дисків як до загального контейнера, який ви нарізуєте, щоб обслуговувати різні цілі: один розділ для даних, один для логів, один для swap, один для «майбутнього», один для «тимчасової продуктивності» і — оскільки ми дорослі, які вже обпеклися — один «на всяк випадок». Це світогляд, сформований десятиліттями традиційних файлових систем і RAID-контролерів, де планування ємності буквально зводилося до таблиць розділів.

В інтерпретації ZFS цей інстинкт проявляється як:

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

Чому це привабливо: розділи здаються контролем. Вони виглядають охайно у таблиці. Вони дозволяють заявити про «майбутню гнучкість», не роблячи важкої роботи — вибору правильної конфігурації vdev на початку. І іноді, особливо в корпоративному середовищі, розділи використовуються як політичний інструмент: «Ми можемо ділити диски між командами.»

Ось проблема: ZFS не цікавиться вашими намірами. Йому важливі шляхи вводу/виводу, домени відмов і геометрія vdev. Розділи не змінюють фізику; вони просто ховають її за гарнішими ярликами.

Жарт №1: Розділяти диски для «гнучкості» ZFS — це як купити більший холодильник, а потім заклеїти полиці, щоб «масштабувати пізніше».

Ментальна модель ZFS: vdev — одиниця істини

Якщо ви хочете перестати проєктувати погані пули, засвоїть це речення: Надмірність і продуктивність ZFS визначаються на рівні vdev, а не на рівні пулу.

Пул: агрегатор

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

Vdev: домен відмов

Vdev будується з одного або кількох пристроїв і має модель надмірності: single disk, mirror, raidz1/2/3, special vdev mirror тощо. Якщо vdev помирає, пул помирає. Ось чому «лише невеликий розділ у однодисковому vdev» — це тихо катастрофічна ідея. Ви додаєте єдину точку відмови до всього пулу.

Пристрої: фізика

ZFS не може ігнорувати, що таке пристрій. Якщо два розділи знаходяться на одному SSD, вони змагаються за один і той же flash translation layer, за один і той же write amplification, за ту саму GC, за той самий бюджет витривалості, за ті самі помилки прошивки і ті самі «сюрпризні» стрибки латентності, коли диск вирішує зайнятися прибиранням.

Datasets: правильне місце для «нарізки»

Якщо вам потрібне розділення — квоти, резервації, політики recordsize, стиснення, снапшоти — ZFS datasets вже забезпечують це чисто. Ви не розділяєте диски для адміністративних меж; ви використовуєте datasets (або zvols), бо вони зберігають топологію пулу і дають контроль над політиками.

Факти та історія, які пояснюють пастку

Трохи контексту допомагає, бо багато поганого дизайну ZFS — це не тупість, а успадковані ментальні моделі.

  1. ZFS створено, щоб покласти край поділу «менеджер томів + файлова система». В еру Solaris UFS плюс менеджер томів означали два шари, які обидва хотіли керувати блоками. ZFS уніфікував це.
  2. Ранні розгортання ZFS часто використовували цілі диски, бо інструменти цього очікували. Розділення з’явилося пізніше як хак сумісності, а не як проєктна мета.
  3. Дебати «цілий диск» проти «розділу» старші за ZFS. Традиційні адміністратори розділяли через MBR/GPT — це був єдиний спосіб розділити пристрої для кількох файлових систем. ZFS зробив це менш актуальним.
  4. Диски з 4K секторами змінили все. Коли диски Advanced Format стали поширеними, невирівнювання та неправильні припущення про сектори спричиняли реальні провали продуктивності. ZFS відповів параметром ashift, який потрібно правильно задавати при створенні vdev.
  5. RAIDZ — не те саме, що RAID5/6 на контролері. ZFS має змінну ширину смуги та семантику copy-on-write, що змінює історію продуктивності та фрагментації порівняно з класичним RAID.
  6. Copy-on-write означає, що «перезапис» — це брехня. ZFS виділяє нові блоки для змін; він не перезаписує на місці. Мислення через розділи часто припускає, що ви можете «захистити» області диска одна від одної. Не можете.
  7. ZIL і SLOG часто неправильно розуміють. ZIL існує в пулі; SLOG — це просто зовнішній пристрій для прискорення певних синхронних записів. Це не «розділ журналу».
  8. Special vdevs потужні й небезпечні. Вони можуть зберігати метадані (і за потреби малі блоки), але якщо вони не надмірні, вони можуть знищити увесь пул.
  9. Поведінка прошивки SSD — більша частина вашої історії латентності, ніж визнають люди. Розділи не ділять прошивку. Вони ділять вашу впевненість.

Як дизайн, орієнтований на розділи, ламає ZFS у реальному житті

1) Ви ненароком створюєте спільні домени відмов

Класичний антипатерн: «Ми розділимо кожен диск на два розділи і зробимо два mirror. Так, якщо ми втратимо диск, кожен mirror втрачає одну сторону і ми все одно в порядку.» На папері це виглядає як надмірність. Насправді кожен mirror залежить від кожного диска. Втратите один диск — обидва mirror деградують. Втратите другий — і ви можете втратити обидва mirror залежно від того, які диски померли.

Стає гірше, коли ви розтягуєтеся через шафи: ви думали, що побудували «два незалежні пули», але насправді створили один пул із корельованими відмовами (та сама партія прошивки, та сама шафа, той самий SAS expander).

2) Ви створюєте конкуренцію за ресурси, яку не можна налаштувати

Якщо два vdev ділять один фізичний пристрій (бо ви використовували розділи), ви створили внутрішню конкуренцію, яку ZFS не бачить. ZFS планує I/O для vdev, вважаючи, що вони незалежні. Коли це не так, виникає дивна поведінка: латентність одного навантаження проскакує в інший vdev, часи scrub зростають, resilver повзає, і система виглядає наче з привидами.

3) Ви прирікаєте себе на невиправні помилки геометрії

У ZFS деякі рішення про макет фактично постійні без перебудови: ashift, ширина RAIDZ і рішення «де живуть метадані», як використання special vdev. Плани, орієнтовані на розділи, часто закладають «ми змінемо пізніше» припущення, що перетворюється на «ми переміграємо пізніше», яке стає «ми житимемо з цим до оновлення апаратури».

4) Ви неправильно розумієте «ефективність простору» і платите за це в операціях

Адміністратори іноді розбивають диски на розділи, щоб зарезервувати місце для майбутніх vdev або створити «рівні групи». ZFS не виграє від невикористаного простору, що сидить у таблиці розділів. Ви не створюєте резерв; ви створюєте покинуту ємність і біль у майбутньому при зміні макету.

5) Ви ускладнюєте відновлення без операційної вигоди

Коли пул хворий, останнє, що вам потрібно — це неоднозначність: «Який це був розділ vdev? Це /dev/sdb2 на цьому хості, але /dev/sdc2 на іншому?» ZFS може використовувати стабільні ідентифікатори пристроїв, але макети з великою кількістю розділів множать кількість ідентифікаторів і шляхів, якими люди можуть помилитися під стресом заміни.

Жарт №2: Якщо ви коли-небудь знайдете себе з ярликом розділу «final2_fixed_really», вітаю — ви виявили технічний борг у його природному середовищі.

Три короткі історії з корпоративного фронту

Коротка історія 1: Інцидент через неправильне припущення («Розділи незалежні»)

У середньому підприємстві команда отримала сервер з пулом, що виглядав «достатньо надмірним». Попередній адміністратор розбив кожен із восьми HDD на два розділи і побудував два RAIDZ1 vdev з розділів. Логіка була така: «два vdev означають паралелізм», і «RAIDZ1 достатній, бо їх два.»

Перший збій був нудним: один диск почав кидати CRC-помилки. Пул залишався онлайн, деградований. Черговий поміняв диск. Почалося resilvering — і одразу продуктивність пішла вбік. Латентність зросла, додатки тайм-аутувалися, команда бази даних почала кружляти як акули.

Потім другий диск вийшов з ладу. Не дивно: того ж віку, тієї ж партії, і стрес при resilver — класичний спосіб виявити маргінальні диски. Сюрприз полягав у тому, що пул помер, хоча «лише два диски вийшли з ладу». Розділи означали, що ці відмови вразили обидва RAIDZ1 vdev так, як ніхто не очікував з діаграми. Пул не міг витримати комбінацію.

Постмортем був болісним, бо корінна причина не була в одному неправильному дії; це було припущення в дизайні, що розділи створюють окремі домени відмов. Вони — ні. Диск — це диск, і надмірність ZFS не розуміє меж ваших розділів як бар’єрів безпеки. «Два vdev» не були незалежними; вони були двома шляхами втратити один і той самий пул.

Що вирішило проблему, так це не героїка. Це була реархітектура під час відновлення: перебудувати пул як mirrors (або RAIDZ2 залежно від цілей ємності), без розділових ігор, і ввести політику «тільки цілі диски» в автоматизації, щоб макет не відкотився.

Коротка історія 2: Оптимізація, що зіграла злий жарт («Маленькі швидкі розділи для метаданих»)

Фінансова організація мала змішане навантаження: багато дрібних файлів, деякі бази даних і процес резервного копіювання, що вів себе як деревоподрібнювач. Хтось прочитав про «special vdev» і надихнувся. Але замість додати виділену пару SSD для special vdev, вони вирізали «швидкий розділ для метаданих» з існуючих SSD, які також служили як data vdev.

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

Потім настав кінець кварталу. Навантаження змінилося: більше синхронних записів, більше хаосу, більше снапшотів. «Розділи для метаданих» почали конкурувати з даними I/O на тих самих SSD. Латентність почала проскакувати, не постійно, але у огидних вибухах. Команда ганялася за привидами: мережа, NFS, блокування бази даних. Тим часом планувальник I/O пулу робив саме те, що йому сказали — ставив special vdev як окрему ємність, хоча він ділив ті самі фізичні пристрої внизу.

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

Виправлення було простим і дорогим: перестати бути хитрим. Перемістити метадані/малі блоки на виділені mirrored SSD, призначені для цієї ролі, і тримати data vdev окремо. Приріст продуктивності повернувся, а стрибки латентності заспокоїлися. План «без витрат» обернувся витратами часу, уваги і репутації — трьома валютами, яких у SRE команд ніколи не вистачає.

Коротка історія 3: Нудна, але правильна практика, що врятувала день («Цілі диски, стабільні ID, відрепетирований процес заміни»)

Інша організація використовувала ZFS для зберігання віртуальних машин. Ніяких хитрощів з розділами. Mirrors для IOPS, окремий mirrored SLOG на SSD з захистом від втрати живлення і виділена пара SSD як special vdev (також у mirror). Документ дизайну був майже образливо нудним.

Але їх операційна практика була справжньою історією: кожен диск мав посилання через стабільні шляхи (by-id), кожний відсік був промаркований, а процедура «замінити диск» відрепетирувалася щоквартально як протипожежний тренування. Вони також тримали невеликий запас ідентичних запасних дисків, бо строки закупівель — це теж тип відмови.

Одного дня диск вийшов з ладу — зник з шини. Черговий не мусив гадати, якого пристрою не стало, не мусив зіставляти розділи і не мусив тлумачити купу двозначних симлінків. Вони виконали процедуру, замінили на аналогічний, почався resilver, і система продовжувала обслуговувати навантаження.

Фішка: під час resilver ще один диск почав логувати помилки. Команда виявила це рано, бо вони дивилися на zpool status і SMART-лічильники як частину тренування. Вони замінили його превентивно, перш ніж це стало катастрофою. Жодної інцидент-бридж-сесії. Жодного панічного копирсання в Slack. Просто нудні, правильні операції зі зберігання — саме ті, що не отримують нагород, але тримають компанію на плаву.

Практичні завдання: команди, що тримають вас чесними

Ось завдання, до яких я насправді тягнусь, коли хтось підсовує мені систему ZFS, що «була ретельно спроєктована» і тепер видає сумні звуки. Кожне завдання містить команду і як інтерпретувати те, що ви бачите.

Завдання 1: Інвентаризація топології пулу (виявити ігри з розділами)

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

        NAME                        STATE     READ WRITE CKSUM
        tank                        ONLINE       0     0     0
          mirror-0                  ONLINE       0     0     0
            ata-SAMSUNG_SSD_...-part1  ONLINE       0     0     0
            ata-SAMSUNG_SSD_...-part1  ONLINE       0     0     0

errors: No known data errors

Інтерпретація: Якщо ви бачите -partX скрізь, запитайте чому. Це може бути нешкідливо (розділи для завантаження плюс цілі «ZFS-партії»), або це може бути чиясь спроба нарізати пристрої для кількох ролей. Шукайте однаковий базовий диск, що з’являється у кількох vdev через різні розділи. Це червоний прапорець.

Завдання 2: Показати vdev з постійними іменами пристроїв

cr0x@server:~$ ls -l /dev/disk/by-id/ | grep -E 'ata-|nvme-' | head
lrwxrwxrwx 1 root root  9 Dec 24 09:10 ata-WDC_WD80... -> ../../sdb
lrwxrwxrwx 1 root root 10 Dec 24 09:10 ata-WDC_WD80...-part1 -> ../../sdb1
lrwxrwxrwx 1 root root 10 Dec 24 09:10 ata-WDC_WD80...-part2 -> ../../sdb2

Інтерпретація: У продакшені посилайтеся на членів vdev через /dev/disk/by-id/..., а не на /dev/sdX. Якщо ви покладаєтесь на /dev/sdX і хтось додасть HBA чи змінить порядок завантаження, ваш наступний ребут стане вечіркою-сюрпризом.

Завдання 3: Перевірити ashift (вирівнювання) по vdev

cr0x@server:~$ sudo zdb -C tank | grep -E 'vdev_tree|ashift' -n
97:        vdev_tree:
130:                ashift: 12

Інтерпретація: ashift: 12 означає 4K сектори. Для більшості сучасних HDD/SSD 12 — безпечна база. Якщо ви бачите ashift: 9 на сучасних дисках, ви можете платити податок продуктивності назавжди, якщо не перебудуєте цей vdev.

Завдання 4: Перевірити реальні розміри секторів з ОС

cr0x@server:~$ sudo lsblk -o NAME,MODEL,SIZE,PHY-SEC,LOG-SEC,ROTA,TYPE | grep -E 'sd|nvme'
sda  INTEL SSDSC2  447.1G    4096    512    0 disk
sdb  WDC WD80EAZZ  7.3T      4096    512    1 disk

Інтерпретація: ZFS пише одиницями 2^ashift. Якщо фізичний сектор 4096, а ваш vdev створено з ashift=9, ви неправильно вирівняні. Це часто проявляється як дивно низькі IOPS і вища латентність під навантаженнями з sync або малими блоками.

Завдання 5: Визначити, чи використовуються special vdev

cr0x@server:~$ sudo zpool status tank | sed -n '/special/,$p'
          special
            mirror-2                ONLINE       0     0     0
              nvme-SAMSUNG_MZ...     ONLINE       0     0     0
              nvme-SAMSUNG_MZ...     ONLINE       0     0     0

Інтерпретація: Якщо існує special vdev і він не замірорений, ставтеся до нього як до інциденту, що чекає на реалізацію. Special vdev можуть зберігати метадані і (за потреби) малі блоки; їх втрата може означати втрату пулу.

Завдання 6: Підтвердити, куди йдуть sync-записи (наявність і стан SLOG)

cr0x@server:~$ sudo zpool status tank | sed -n '/logs/,$p'
          logs
            mirror-1                ONLINE       0     0     0
              ata-INTEL_SLOG_A      ONLINE       0     0     0
              ata-INTEL_SLOG_B      ONLINE       0     0     0

Інтерпретація: SLOG допомагає тільки для синхронних записів (NFS з sync, бази даних, налаштовані на durable тощо). Якщо ваш «SLOG» — це розділ на зайнятому data SSD, ви, ймовірно, обміняли передбачувану латентність на непередбачувану.

Завдання 7: Побачити I/O по vdev і виявити повільний член

cr0x@server:~$ sudo zpool iostat -v tank 1 5
                    capacity     operations     bandwidth
pool              alloc   free   read  write   read  write
----------------  -----  -----  -----  -----  -----  -----
tank              2.10T  5.10T    120    380  12.3M  45.1M
  mirror-0        1.05T  2.55T     60    190   6.1M  22.6M
    sdb            -      -       60    190   6.1M  22.6M
    sdc            -      -       60    190   6.1M  22.6M
  mirror-1        1.05T  2.55T     60    190   6.2M  22.5M
    sdd            -      -       60    190   6.2M  22.5M
    sde            -      -       60    190   6.2M  22.5M

Інтерпретація: Коли один vdev значно повільніший, хвостова латентність пулу слідує за ним. Якщо ви побудували vdev з розділів на одному фізичному диску, вивід iostat може виглядати «збалансованим», тоді як фізичний пристрій перевантажений — бо ZFS не бачить спільного вузького місця.

Завдання 8: Перевірити властивості на рівні dataset замість вигадування розділів

cr0x@server:~$ sudo zfs get -o name,property,value,source compression,recordsize,atime,sync tank/app
NAME      PROPERTY     VALUE   SOURCE
tank/app  compression  lz4     local
tank/app  recordsize   128K    local
tank/app  atime        off     local
tank/app  sync         standard default

Інтерпретація: Тут ви робите налаштування під робоче навантаження. Вам не потрібен «розділ журналу» для додатку з великою кількістю логів; вам потрібен відповідний recordsize, можливо atime=off, можливо окремий dataset для різних I/O-патернів.

Завдання 9: Спостерігати латентність у реальному часі (сироватка правди)

cr0x@server:~$ sudo zpool iostat -r -v tank 1 3
                    capacity     operations     bandwidth    total_wait  disk_wait
pool              alloc   free   read  write   read  write   ---------   ---------
tank              2.10T  5.10T    120    380  12.3M  45.1M     12ms        8ms
  mirror-0        1.05T  2.55T     60    190   6.1M  22.6M     10ms        7ms
  mirror-1        1.05T  2.55T     60    190   6.2M  22.5M     14ms        9ms

Інтерпретація: Якщо disk_wait високий, фізичні пристрої повільні або перевантажені. Якщо total_wait значно вищий за disk_wait, можливо, ви завантажені CPU, маєте дефіцит пам’яті або стоїте за чергами ZFS (часто симптом завеликих vdev або патологічних sync-навантажень).

Завдання 10: Підтвердити навантаження на ARC і чи пам’ять — це ваш вузький вузол

cr0x@server:~$ sudo arcstat 1 3
    time  read  miss  miss%  dmis  dm%  pmis  pm%  mmis  mm%  arcsz     c
09:21:01   520    40      7    10   25    20   50    10   25   28G    32G

Інтерпретація: Високі показники miss при маленькому arcsz відносно навантаження можуть штовхати I/O на диск і робити все схоже на «проблему зберігання», хоча насправді це питання розміру пам’яті. Розділення цього не вирішить; воно лише дає вам нові місця для помилок.

Завдання 11: Статус scrub і усвідомлення впливу

cr0x@server:~$ sudo zpool status tank
  pool: tank
 state: ONLINE
scan: scrub in progress since Tue Dec 24 08:10:15 2025
        1.20T scanned at 520M/s, 600G issued at 260M/s, 2.10T total
        0B repaired, 28.57% done, 0 days 02:10:33 to go

Інтерпретація: Scrub корисні; scrub також створюють навантаження. Якщо scrubs стабільно вбивають продуктивність, у вас, ймовірно, проблема геометрії vdev (занадто широкі RAIDZ для IOPS-навантажень) або спільне вузьке місце пристрою (ігри з розділами), або просто замало шпинделів.

Завдання 12: Правильно замінити диск (а не гадати з розділами)

cr0x@server:~$ sudo zpool replace tank /dev/disk/by-id/ata-WDC_OLD_DRIVE /dev/disk/by-id/ata-WDC_NEW_DRIVE
cr0x@server:~$ sudo zpool status -v tank
  pool: tank
 state: DEGRADED
scan: resilver in progress since Tue Dec 24 09:02:11 2025
config:
        NAME                                 STATE
        tank                                 DEGRADED
          mirror-0                           DEGRADED
            replacing-0                      DEGRADED
              ata-WDC_OLD_DRIVE              UNAVAIL
              ata-WDC_NEW_DRIVE              ONLINE  (resilvering)
            ata-WDC_PEER_DRIVE               ONLINE

Інтерпретація: Використовуйте стабільні ID. Замінюйте цілі пристрої, коли це можливо. Коли ваш пул побудований з розділів, операції заміни стають більш схильними до помилок, бо ви керуєте кількома цілями partX на диск.

Завдання 13: Виявити випадкове багаторазове використання фізичного диска

cr0x@server:~$ sudo zpool status -P tank | grep -E '/dev/disk/by-id/.*-part' | sed 's/-part[0-9]\+//g' | sort | uniq -c | sort -nr | head
      2 /dev/disk/by-id/ata-SAMSUNG_SSD_870_EVO_S5...
      1 /dev/disk/by-id/ata-WDC_WD80EAZZ_7SG...

Інтерпретація: Якщо той самий базовий пристрій з’являється кілька разів (count > 1) після видалення суфіксів розділів, ймовірно, у вас один диск, що живить кілька членів vdev. Іноді це навмисно для завантаження; часто це запах дизайну.

Завдання 14: Перевірити feature flags пулу і припущення щодо версій

cr0x@server:~$ sudo zpool get -H -o property,value feature@async_destroy feature@spacemap_histogram tank
feature@async_destroy      enabled
feature@spacemap_histogram active

Інтерпретація: Це не про «розділ проти цілого диска», але воно запобігає пов’язаному класу відмов: спробі імпортувати пул на хості, який не підтримує його фічі. Люди, що люблять розділи, також часто вважають, що «ми можемо імпортувати куди завгодно». Не завжди.

Швидкий план діагностики (пошук вузьких місць)

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

Перш за все: чи пул здоровий і не виконує надзвичайну роботу?

cr0x@server:~$ sudo zpool status -x
all pools are healthy

Якщо не здоровий: припиніть діагностувати «продуктивність». Ви діагностуєте «виживання». Деградований vdev, resilver або інтенсивне виправлення помилок буде домінувати над усім.

Друге: чи зараз триває scrub/resilver?

cr0x@server:~$ sudo zpool status tank | sed -n '1,25p'

Інтерпретація: Resilver — законна причина зниження пропускної здатності. Якщо ваш пул стає непридатним під час рутинних scrubs, це проблема проєктної місткості: недостатньо IOPS-запасу або макет, що надто оптимізований для ємності в шкоду паралелізму.

Третє: який vdev найповільніший під навантаженням?

cr0x@server:~$ sudo zpool iostat -r -v tank 1 10

Інтерпретація: Шукайте vdev із вищими часами очікування. У змішаних пулах найповільніший vdev тягне хвостову латентність. Якщо ви бачите непослідовні очікування, що корелюють між кількома vdev, підозрівайте спільні фізичні пристрої (розділення) або проблеми з backplane/HBA.

Четверте: це тиск синхронних записів (SLOG / ZIL) чи загальний випадковий I/O?

cr0x@server:~$ sudo zfs get -r -o name,property,value,source sync tank | head
NAME      PROPERTY  VALUE     SOURCE
tank      sync      standard  default
tank/app  sync      standard  default

Інтерпретація: Якщо навантаження примушує sync (NFS, бази даних) і у вас немає належного SLOG, латентність стрибне. Якщо SLOG є, але він не має захисту від втрати живлення або перевантажений (або це розділ на зайнятих пристроях), ви отримаєте «швидко іноді, жахливо іноді».

П’яте: чи тисне на вас ARC/пам’ять, змушуючи йти на диск?

cr0x@server:~$ free -h
              total        used        free      shared  buff/cache   available
Mem:           64Gi        52Gi       1.2Gi       1.0Gi        11Gi        8Gi
Swap:          0B          0B          0B

Інтерпретація: Низька доступна пам’ять при високому дисковому навантаженні може виглядати як «повільне зберігання». ZFS любить RAM; його голодування змушує диски робити дурну роботу.

Шосте: чи вузьке місце — CPU, стиснення або контрольні суми?

cr0x@server:~$ top -b -n1 | head -20

Інтерпретація: Якщо CPU зашитий під час інтенсивних записів зі стисненням, можливо, ви обмежені обчислювально. Це не погано — стиснення може бути вигідним — але треба знати, за що платите.

Сьоме: перевірити помилки на рівні пристрою та проблеми лінку

cr0x@server:~$ sudo dmesg -T | grep -E 'ata[0-9]|nvme|sd[a-z]:|I/O error|link reset' | tail -20

Інтерпретація: CRC-помилки, скидання лінків і таймаути можуть маскуватися під «ZFS повільний». Часто це кабель, expander або прошивка HBA. Розділи цього не спричиняють, але макети з розділами ускладнюють визначення, який фізичний диск справді хвора.

Поширені помилки: конкретні симптоми та виправлення

Помилка 1: Використання розділів одного диска в різних vdev

Симптом: Випадкові стрибки латентності, які не відповідають розподілу iostat на рівні ZFS; scrubs/resilvers уповільнюють «усе»; непередбачувана хвостова латентність.

Чому це відбувається: ZFS вважає, що має більше незалежних пристроїв, ніж насправді.

Виправлення: Перебудувати з одним призначенням на фізичний пристрій. Якщо вам потрібні кілька «класів» (data, special, slog), використовуйте окремі фізичні пристрої для кожного класу і дзеркальні критичні.

Помилка 2: Додавання однодискового «special» або «log» vdev, бо це «тільки метадані» або «тільки журнал»

Симптом: Втрата пулу після виходу одного пристрою; неможливість імпортувати; раптова «I/O error», коли цей пристрій помирає.

Чому так відбувається: Special vdev і SLOG мають різні профілі ризику. SLOG зазвичай можна втратити без втрати пулу (ви втрачаєте недавні синхронні транзакції). Special vdev може бути критичним для пулу залежно від того, що він зберігає.

Виправлення: Дзеркальте special vdev. Використовуйте для SLOG пристрої з PLP. Уникайте «хитромудрих» розділів для критичних ролей.

Помилка 3: Думати, що розділи вирішують «майбутнє розширення»

Симптом: Покинута ємність; дивні розміри vdev; неможливість чисто додати нові vdev; нерівномірна продуктивність після розширення.

Чому так відбувається: Розширення ZFS — це додавання vdev, а не розширення розділів. Потрібні узгоджені vdev з послідовними характеристиками продуктивності.

Виправлення: Плануйте розширення одиницями vdev. Mirrors розширюються додаванням нових mirrors. RAIDZ розширюється додаванням ще одного RAIDZ vdev (або заміною дисків на більші та очікуванням autoexpand, якщо підтримується).

Помилка 4: Неправильний ashift через «клонування працювало на старому сервері»

Симптом: Дрібні випадкові записи дивно повільні; високе write amplification; прискорене зношення SSD.

Виправлення: Створюйте vdev з правильним ashift з самого початку. Якщо помилково задано, чесним вирішенням буде міграція/перебудова. Не намагайтеся «вирізати» це розділами.

Помилка 5: Сприймати RAIDZ як функцію продуктивності для IOPS-наситивих навантажень

Симптом: Зберігання VM відчувається повільним; латентність бази даних висока; пропускна здатність в тестах в порядку, але реальні навантаження страждають.

Виправлення: Використовуйте mirrors для навантажень, чутливих до IOPS. RAIDZ — для ємності/послідовної пропускної здатності. Якщо потрібно RAIDZ, тримайте ширини розумними і розумійте вікна відновлення.

Помилка 6: Надмірне розділення для «стандартної завантажувальної розмітки» без документації

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

Виправлення: Якщо потрібно розділяти для завантаження (часто в деяких конфігураціях), тримайте це мінімальним і однорідним і автоматизуйте маркування. Робіть членів ZFS vdev стабільними і очевидними через by-id і послідовні номери розділів.

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

Покроково: проєктування нового пулу без «мислення через розділи»

  1. Визначте домен відмов перш за все. Один сервер? Одна шафа? Кілька HBA? Визначте, що для вашого середовища означає «одна відмова».
  2. Виберіть тип vdev залежно від навантаження.
    • VMs/бази даних/чутливі до латентності: mirrors (більше vdev = більше паралелізму).
    • Резервні копії/медіа/послідовні навантаження: RAIDZ2/3 (ефективність ємності).
  3. Виберіть ashift цілеспрямовано. За замовчуванням використовуйте 12, якщо немає вагомої причини інакше.
  4. Вирішіть, чи потрібен special vdev. Лише якщо метадані/мала блокова продуктивність важлива і ви можете дзеркалити його хорошими SSD.
  5. Вирішіть, чи потрібен SLOG. Тільки якщо у вас є реальний тиск синхронних записів і ви можете використовувати пристрої з захистом від втрати живлення.
  6. Використовуйте datasets для розділення політик. Квоти, резервації, recordsize, стиснення, снапшоти — робіть це там.
  7. Стандартизируйте іменування пристроїв. Будуйте і експлуатуйте за допомогою /dev/disk/by-id.
  8. Документуйте процедуру заміни. Потім відрепетируйте її.

Покроково: створення пулу (приклад) з використанням цілих дисків і стабільних ID

cr0x@server:~$ sudo zpool create -o ashift=12 tank \
  mirror /dev/disk/by-id/ata-WDC_DISK_A /dev/disk/by-id/ata-WDC_DISK_B \
  mirror /dev/disk/by-id/ata-WDC_DISK_C /dev/disk/by-id/ata-WDC_DISK_D

cr0x@server:~$ sudo zfs set compression=lz4 atime=off tank
cr0x@server:~$ sudo zfs create tank/app
cr0x@server:~$ sudo zfs set recordsize=16K tank/app

Інтерпретація: Mirrors дають IOPS через паралелізм; datasets дають політики. Ніяких розділових гімнастик.

Покроково: додавання mirrored special vdev (приклад)

cr0x@server:~$ sudo zpool add tank special mirror \
  /dev/disk/by-id/nvme-SAMSUNG_SPECIAL_A \
  /dev/disk/by-id/nvme-SAMSUNG_SPECIAL_B

cr0x@server:~$ sudo zfs set special_small_blocks=16K tank

Інтерпретація: Ось як прискорити метадані/малі блоки, не обманюючи себе щодо доменів відмов. Дзеркальні, виділені пристрої.

Покроково: додавання mirrored SLOG (приклад)

cr0x@server:~$ sudo zpool add tank log mirror \
  /dev/disk/by-id/ata-INTEL_PLP_SLOG_A \
  /dev/disk/by-id/ata-INTEL_PLP_SLOG_B

Інтерпретація: Дзеркальний SLOG зменшує ризик і покращує консистентність для sync-наситих навантажень. Не підробляйте це розділом на вже зайнятих pool SSD.

Операційний чекліст: що стандартизувати, щоб люди не мусили бути ідеальними

  • Завжди використовуйте шляхи by-id при створенні і заміні пулів.
  • Промаркуйте відсіки і ведіть внутрішню відповідність bay-to-serial.
  • Плануйте scrubs і відстежуйте їх тренд тривалості з часом.
  • Сповіщайте про SMART pre-fail і ZFS read/write/checksum помилки.
  • Тримайте запасні диски (або гарантований шлях постачання) для кожного класу пристроїв.
  • Відрепетируйте zpool replace і zpool clear робочі процеси в безпечному середовищі.

FAQ

1) Чи завжди погано використовувати розділи з ZFS?

Ні. Звично використовують невеликий EFI/boot-розділ, а потім ZFS-розділ для члена пулу. Погано — використовувати розділи, щоб прикидатися, що один фізичний пристрій — кілька незалежних пристроїв, або змішувати ролі на одному диску так, щоб створювати приховану конкуренцію та корельовані відмови.

2) Чому «один поганий vdev вбиває пул» так важливо?

Тому що це перевертає спосіб мислення про ризик. В LVM-світі ви можете втратити PV і, можливо, лише один том. У ZFS, якщо ви додаєте однодисковий vdev (навіть крихітний), ви додали єдину точку відмови до всього пулу.

3) Чи можу я розбити диски на розділи, щоб створити більше vdev для продуктивності?

Можете, але не повинні. Ви не створюєте більше IOPS; ви створюєте більше черг, які врешті потрапляють на той самий фізичний пристрій. ZFS буде планувати як ніби vdev незалежні, що робить продуктивність менш передбачуваною і може погіршити латентність під навантаженням.

4) Який правильний спосіб ізолювати навантаження, якщо не розділами?

Використовуйте datasets (або zvols) з квотами, резерваціями та властивостями на рівні dataset. Якщо вам потрібна жорстка ізоляція на рівні пристрою, використовуйте окремі пули на окремих фізичних пристроях — не розділи на тих самих шпинделях/SSD.

5) Чи потрібен мені SLOG для NFS?

Лише якщо ваше NFS-навантаження робить синхронні записи (поширено для зберігання VM, деяких конфігурацій баз даних і певних опцій експортів NFS). Якщо ваше навантаження здебільшого async, SLOG навряд чи допоможе. Якщо він потрібен, використовуйте пристрої з захистом від втрати живлення і бажано дзеркальні.

6) Чи варті special vdev?

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

7) Mirrors vs RAIDZ: що є «продакшн за замовчуванням»?

Для загального призначення, чутливих до латентності навантажень (VM, бази даних), mirrors — безпечніший вибір, бо вони збільшують IOPS з кожним vdev і швидше відновлюються. RAIDZ чудовий для ефективності ємності і послідовної пропускної здатності, але не є чарівним для випадкового I/O.

8) Якщо мій пул вже побудований з розділів, що робити?

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

9) Чи «перебалансує» ZFS дані, коли я додаю нові vdev?

Не в тому сенсі, який люди сподіваються. Нові записи, як правило, підуть у новий простір, але існуючі блоки залишаються там, де вони є, поки не будуть перезаписані (або поки ви не використаєте специфічні стратегії ребалансування). Це ще одна причина, чому плани «ми виправимо пізніше» з розділами старіють погано.

10) Який найшвидший ознака, що ваша команда мислить розділами, а не ZFS?

Якщо в документі дизайну більше розмов про «нарізання дисків», ніж про кількість vdev, ширину vdev, домени відмов і поведінку відновлення — ви в зоні мислення розділів.

Висновок

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

Якщо ви хочете пул ZFS, що поводить себе як професійна система — передбачуваний, діагностований і життєздатний — проєктуйте навколо vdev, використовуйте datasets для розділення, тримайте ролі на виділених фізичних пристроях і стандартизуйте операційні основи. Нудний підхід перемагає, не тому що він нудний, а тому що він залишає менше простору для фізики, щоб здивувати вас.

← Попередня
Розмір DDT у ZFS: прогнозування потреб у RAM перед увімкненням дедуплікації
Наступна →
Червоне кільце смерті: теплове лихо Xbox 360, що коштувало мільярди

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