ZFS redundant_metadata: коли більше копій метаданих має значення

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

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

Підступ у тому, що «більше копій» не означає автоматично «краще». Додаткові копії метаданих можуть врятувати вас від такого коруптування, через яке досвідчені інженери мовчки дивляться на zpool status — але вони також можуть непомітно додати write amplification і перетворити вже I/O-забитий пул на чергову катастрофу. Ця стаття про те, коли redundant_metadata виправдовує витрати, коли ні, і як відрізнити це в production без гадань.

Що redundant_metadata насправді робить

redundant_metadata — це властивість dataset у ZFS, яка впливає на те, скільки копій метаданих ZFS зберігає. Найпоширеніші значення, які ви побачите:

  • all: зберігати резервні копії всіх метаданих (тобто намагатися тримати додаткові копії).
  • most: зберігати резервні копії більшості метаданих.
  • none: не зберігати додаткові копії метаданих (окрім тієї надмірності, яку вже забезпечує розклад ваших vdev).

Це не те саме, що властивість copies. copies=2 дублює дані й метадані на рівні dataset, що суттєво збільшує використання місця. redundant_metadata орієнтується тільки на метадані, які зазвичай набагато менші за користувацькі дані — поки не стають великими (подумайте про мільйони маленьких файлів, агресивні snapshot-и або навантаження, яке багато працює з метаданими: maildir, шари контейнерів, build-кеші).

Важлива нюанс: ZFS вже має надмірність на рівні vdev (mirror, RAIDZ). redundant_metadata стосується додаткових копій поверх цього. На mirror ви вже маєте дві або більше копій кожного блоку, бо весь vdev дубльований. На RAIDZ кожен блок захищений парністю, але це все одно один логічний блок при записі. Додаткові копії метаданих можуть дати альтернативні фізичні екземпляри того ж блоку метаданих, що змінює історію відновлення у випадках тихої корупції або проблем на рівні секторів, які парність не може виправити (наприклад, повторювані помилки читання в певному регіоні або пристрій, що повертає неправильні дані, змушуючи шлях перевірки контрольної суми робити повторні спроби).

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

Жарт #1 (коротко й по темі): Метадані — як DNS: нікому не потрібні, поки не поламаються, а потім раптом це «найважливіший сервіс у нас».

Що тут вважається «метаданими»?

Метадані ZFS включають такі речі, як вказівники на блоки, непрямі блоки, dnodes (метадані файлу), структури каталогів, space map-и та інші структури на диску, що використовуються для знаходження й перевірки ваших даних. Частина метаданих — глобальна для пулу (MOS та інші), частина — специфічна для dataset. На практиці, якщо ви дебажите страшну ситуацію, «метадані», які вас цікавлять, — це все, що перешкоджає файловій системі коректно пройти до вмісту файлу.

Не всі метадані однаково важливі. Зіпсований вміст файлу може бути одиничним вкладенням клієнта, яке можна відновити зі snapshot-а. Зіпсовані метадані можуть зробити цілі dataset-и неможливими для монтування або викликати помилки обходу, що блокують саме відновлення (а це справжній кошмар: у вас є бекапи, але ви не можете їх перерахувати).

Чому метадані — це те, що ви насправді не можете втратити

ZFS працює за принципом copy-on-write. Кожного разу, коли змінюється блок, система записує нові блоки й потім оновлює вказівники на нові блоки. Ось чому ZFS так гарно забезпечує консистентність: він не перезаписує живі структури на місці; він будує нове дерево і в кінці «перемикає» кореневий вказівник. Цей дизайн має наслідки:

  • Частота змін метаданих може бути дуже високою, навіть коли користувацькі дані «стабільні».
  • «Форма» ваших метаданих впливає на продуктивність (більше індексацій, більше маленьких випадкових I/O).
  • Метадані роблять snapshot-и можливими, але snapshot-и також зберігають історичні метадані, що може збільшити кількість блоків метаданих, які мають залишатися читаємими.

Операційно, збої ZFS зазвичай бувають двох типів:

  • Очевидні відмови пристроїв: диск помер, SMART показує проблеми, mirror деградував, ви його міняєте, робите resilver. Неприємно, але рутинно.
  • Неочевидна корупція та часткова нечитаємість: усе виглядає нормально, поки scrub або доступ до конкретного блоку не виявить помилку контрольної суми або постійну помилку. Блоки метаданих тут непропорційно болючі, бо вони можуть бути на критичних шляхах: монтування, перерахунок каталогів, операції зі snapshot-ами, send/receive, навіть scrubs.

Додаткові копії метаданих не врятують вас від усіх катастроф. Вони не виправлять «ой, ми знищили пул» і не зроблять RAIDZ дзеркалом. Але вони можуть перетворити інцидент корупції з «потрібен вікно відновлення і купа кави» у «scrub виправив це, і ми продовжили роботу».

Як ZFS розміщує додаткові копії (і де не може)

У ZFS давно існує механізм «ditto blocks» (додаткові копії метаданих). Інтенція проста: якщо один екземпляр поганий, інший може бути хорошим, і контрольні суми дозволяють ZFS вибрати вірний. Це концептуально схоже на наявність кількох реплік, але в межах одного пулу і кероване правилами аллокатора.

Є обмеження:

  • Не все копіюється однаково. Деякі метадані обробляються особливо; деякі можуть бути занадто великі або надто часті для розумного дублювання.
  • Копії мають кудись лягти. Якщо ваш пул малий, фрагментований або обмежений вузьким набором пристроїв, «додаткові копії» можуть опинитися не такими незалежними, як ви думаєте. Дві копії на одному й тому ж збійному диску не дають надмірності; вони дають оптимізм.
  • Спеціальний vdev змінює правила гри. Якщо ви використовуєте special vdev для метаданих, то розміщення і надмірність метаданих можуть стати і кращими, і гіршими: кращими, бо метадані на швидких пристроях, гіршими, бо ви щойно створили «шари метаданих», які мають бути належно надмірними, або ви отримали єдину точку відмови з кращою латентністю.

Також: redundant_metadata не переписує ваш пул ретроспективно. Воно впливає на нові записи. Існуючі блоки метаданих зазвичай залишаються як є, поки їх не перезаписати через природний churn, або поки ви не примусите перезапис специфічними тактиками (що може бути ризиковано і залежати від навантаження).

Mirrors, RAIDZ і хибне відчуття «вже є надмірність»

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

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

Жарт #2 (коротко й по темі): RAIDZ парність як страхування: добре, поки ви не дізнаєтесь, що франшиза — «перебудувати пул у вихідні».

Коли більше копій метаданих справді важливе

Ось ситуації, де redundant_metadata зазвичай виправдовує себе, на основі того, як відмови проявляються в реальних системах.

1) Навантаження, що багато працюють з метаданими (мільйони файлів, крихітні файли, глибокі дерева)

Якщо ви запускаєте щось, що створює величезну кількість файлових об’єктів — CI build-кеші, шари контейнерів, mirror-репозиторії пакетів, поштові спули, сховища артефактів, великі монорепозиторії — ваші «метадані» перестають бути дрібницею. Вони стають повноцінним споживачем ємності і продуктивності. Це саме те середовище, де корупція метаданих особливо руйнівна: обхід торкається великої кількості блоків метаданих, і один поганий блок каталогу може блокувати доступ до великих логічних ділянок даних.

Додаткові копії корисні, бо ймовірність натрапити на поганий блок метаданих зростає з кількістю цих блоків. Це статистика, а не забобон.

2) Довге збереження snapshot-ів або агресивні графіки знімків

Snapshot-и зберігають історичні версії метаданих, а не лише дані. Коли ви зберігаєте багато snapshot-ів, ви зберігаєте старі метадані. Якщо якась частина цих метаданих стає нечитаємою, це може зламати операції типу zfs list -t snapshot, zfs destroy (так, навіть видалення може бути заблоковане) і zfs send. Це як зберігати роки чеків у коробці — все добре, поки потрібний документ не виявиться тим, на який пролили каву.

redundant_metadata=all може зменшити шанс того, що конкретний блок метаданих стане єдиною точкою відмови.

3) Пули з історією помилок контрольних сум або нестабільним обладнанням

Ми всі хочемо корпоративного обладнання. Іноді ви успадковуєте «best effort» обладнання з історією закупівель «це була вигідна пропозиція». Якщо ви бачили періодичні помилки контрольних сум під час scrub-а або вам доводилося замінювати диски через помилки читання більше одного разу, redundant metadata може бути практичним зменшувачем ризику.

Але будьте чесні: якщо ви регулярно бачите помилки контрольних сум, перший чинник виправлення — зазвичай апаратне забезпечення, кабелі, HBA, прошивка і живлення. redundant_metadata — не заміна стабільному I/O-шляху; це пасок безпеки, а не кермо.

4) RAIDZ пули, де обмеження — читальні IOPS метаданих

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

5) Правильно спроектовані special vdev

Якщо у вас є special vdev з дзеркалами SSD, присвячений метаданим (і, опціонально, маленьким блокам), ви можете зробити метадані одночасно швидшими й більш стійкими — якщо special vdev сам по собі належно надмірний і моніториться. В таких архітектурах встановлення redundant_metadata=all для критичних наборів даних може стати різницею між «метадані швидкі» і «метадані швидкі і виживають під дивним режимом відмови SSD».

Коли це шкодить: компроміси продуктивності та простору

redundant_metadata — це не безкоштовний обід. Воно може вдарити по трьох місцях: write amplification, поведінка фрагментації і планування ємності.

Write amplification і малі випадкові записи

Записи метаданих зазвичай малі та випадкові. Їх дублювання означає більше маленьких випадкових записів. На HDD пулах це спосіб перетворити «прийнятну латентність» у «чому весь цей 200ms». На SSD ви можете не відчути це відразу, але ви все одно збільшуєте обсяг записів і потенційно впливаєте на знос і поведінку garbage collection.

Якщо ваше навантаження багато працює з синхронними операціями (бази даних з sync=standard і багатьма fsync, NFS з sync-семантикою), шлях метаданих знаходиться на критичному ланцюжку латентності. Додаткові записи метаданих можуть проявитися як збільшення часу коміту, що перетворюється на хвостову латентність додатків. Ніхто не дзвонить команді зберігання через середню латентність.

Витрати простору, які непомітні, поки не стануть проблемою

Накладні витрати на метадані зазвичай малі в порівнянні з даними. «Зазвичай» робить багато роботи в цьому реченні. Якщо ви зберігаєте мільярди малих об’єктів, активно використовуєте xattr, або тримаєте глибоку історію snapshot-ів, метадані можуть бути суттєвими. Додаткові копії метаданих можуть підштовхнути вас до високого заповнення пулу, а високий рівень заповнення погіршує поведінку аллокатора, збільшує фрагментацію і погіршує продуктивність.

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

Не правильна «заміна» для кращої надмірності

Якщо ваша реальна мета — «хочу, щоб цей dataset пережив дві відмови дисків», redundant_metadata не є інструментом для цього. Обирайте топологію mirror/RAIDZ залежно від вимог. Додаткові копії метаданих допомагають при певних класах корупції і локалізованої нечитаємості; вони не змінюють фундаментальну ступінь стійкості до відмов, як це робить надмірність vdev.

Факти та контекст, які можна використати в дискусіях

Ось короткі, конкретні пункти, які допомагають у design review, коли хтось каже «навіщо нам взагалі говорити про метадані?»

  1. ZFS створювався з end-to-end контрольними сумами, тому він може виявляти тиху корупцію замість того, щоб видавати погані дані мовчки. Це виявлення корисне лише якщо є дійсне альтернативне джерело (сторона mirror, реконструкція парністю або додаткова копія).
  2. Copy-on-write робить консистентність дешевою, але метадані зайняті. Навіть «малі» зміни можуть торкатися кількох блоків метаданих: оновлення dnode, непрямі блоки, оновлення spacemap і т.д.
  3. Термін «ditto blocks» передує сучасній назві властивості і відображає початкову ідею: тримати додаткові копії критичних метаданих, щоб один поганий сектор не відключив обхід пулу.
  4. Scrub-и — це не просто «перевірки», це робочі процеси відновлення на надмірних vdev: ZFS читає, перевіряє контрольні суми і може лікувати, переписуючи з доброї копії. Додаткові копії метаданих можуть підвищити шанс, що добра копія існує.
  5. Метадані мають дрібно-блочний I/O, що якраз є найгіршим сценарієм для HDD vdev і парних розкладок: маленькі, випадкові, чутливі до латентності операції.
  6. RAIDZ має «податок реконструкції»: коли сектор поганий, зчитування блоку може вимагати читання кількох колонок і реконструкції. Для метаданих цей податок вражає часті операції (обходи каталогів, перерахунок snapshot-ів).
  7. Високе заповнення пулу змінює поведінку аллокатора, часто збільшуючи фрагментацію і розкидаючи I/O метаданих. Додаткові копії метаданих посилюють тиск на вільний простір раніше.
  8. Special vdev ввели для вирішення вузького місця IOPS метаданих, перемістивши метадані на швидші пристрої; але вони також вводять новий домен відмов, який має бути дзеркальним (або кращим), бо його втрата може бути катастрофічною.
  9. «Бекапи є» — це не те саме, що «можна відновити». Якщо корупція метаданих заважає перераховувати snapshot-и або читати send-потоки, у вас можуть бути біти на диску й ви все одно будете заблоковані операційно.

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

Міні-історія №1: Інцидент через хибне припущення

Ми успадкували кластер зберігання, який «мав надмірність», згідно з документом передачі. Пул був RAIDZ2, багато дисків, і панелі були зелені. Припущення команди було таким: парність = безпека, тому налаштування метаданих — академічне питання.

Потім банальна подія: почався тижневий scrub, і через день розробники поскаржилися, що контейнерний реєстр «випадково зависає». Не впав — просто зависав. Пул не був переповнений, очевидних відмов пристроїв не було. Але латентність зросла під час операцій, що інтенсивно працювали з метаданими: перелік тегів, garbage collection і отримання старих шарів. Команда додатків підозрювала мережу. Мережа підозрювала DNS. Команда зберігання підозрювала все й ніщо одночасно.

zpool status показав помилки контрольної суми на одному диску, але vdev залишався ONLINE. RAIDZ2 «обробляв це». Хибне припущення було в тому, що «обробляє» означає «немає впливу на користувача». Насправді кожного разу, коли ZFS натрапляв на певні блоки метаданих, що жили в маргінальному регіоні диска, він платив податок реконструкції. Під час scrub-а ці читання метаданих стали частими й дорогими. Система була коректна; вона також була повільна.

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

Міні-історія №2: Оптимізація, що обернулася проти

Інше середовище: система збірки, що продукувала мільйони маленьких артефактів. Пул був SSD-RAIDZ, і команда хотіла вичавити максимум ємності. Хтось прочитав, що додаткова надмірність метаданих «марнує місце» і встановив redundant_metadata=none для артефактних dataset-ів. Здавалося безпечно. Scrub-и були чисті. Графіки виглядали добре. Промоушни обговорювалися.

Місяці потому проблема прошивки (не катастрофічна, просто дратівлива) спричинила випадкові помилки читання на підмножині блоків одного SSD. З RAIDZ ZFS реконструював. Знову «оброблено». Але навантаження було метаданевим: обходи каталогів, масові stat-операції і операції з утриманням snapshot-ів під час cleanup-а. Одного дня завдання очищення почало падати при спробі destroy старих snapshot-ів через «I/O error» на dataset-і. Не весь пул. Не навіть всі snapshot-и. Просто певні операції, що торкалися специфічних структур метаданих.

Тепер відкат: оскільки метадані не мали додаткових фізичних копій, варіантів відновлення було менше. RAIDZ міг реконструювати деякі блоки, але один блок став постійно нечитаємим після повторних спроб; ZFS повідомив про постійні помилки, пов’язані з метаданими. Dataset став частково невпорядкованим: перелік був повільним і помилковим, cleanup не вдавався, і send мав проблеми. В результаті ми змушені були виконати більш руйнівне відновлення: відновлення з реплікації, що мала чисту копію, що коштувало часу і репутації.

Урок не в «завжди ставте redundant_metadata=all». Урок у тому, що «оптимізація» була зроблена без розуміння моди відмов, яку вона віддавала. Оптимізацію ємності легко обґрунтувати; складність відновлення важче кількісно оцінити, поки ви не живете в ній.

Міні-історія №3: Нудна, але правильна практика, що врятувала день

Третя історія — найменш гламурна: команда, що робила рутинні scrub-и, тримала розумний рівень заповнення пулу і мала чистий поділ dataset-ів з розумними властивостями. Вони також мали політику: набори даних, що багато працювали з метаданими, отримували додатковий захист, і вони використовували mirrored special vdev для метаданих на своїх найнавантаженіших пулах.

Одного ранку хост перезавантажився після обслуговування електроживлення. Він піднявся, але кілька сервісів були повільні. Нічого не було «впало», і саме в такій ситуації люди витрачають півдня, вказуючи пальцями. Інженер зберігання запустив scrub і одразу побачив помилки контрольної суми, які були виправлені. Система вилікувалася сама, бо мала звідки лікуватися.

Це не кінець: корінь проблеми простежили до хиткого HBA-кабелю, що іноді корумпував дані в польоті. Причина, чому це не стало повноцінним інцидентом, була нудною: контрольні суми виявили це, надмірність відновила, і scrub-и швидко це виявили. Вони замінили кабель, перевірили й продовжили роботу. Ніяких героїзмів. Жодного відновлення у вихідні. Жодної драматичної наради «ми ледь не втратили все».

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

Практичні завдання: команди та інтерпретація

Нижче — практичні завдання, які ви можете виконати на системі ZFS. Команди записані для shell у стилі Linux з утилітами OpenZFS. Налаштуйте імена pool/ dataset під своє середовище.

Завдання 1: Перевірити поточне значення redundant_metadata (і наслідування)

cr0x@server:~$ zfs get -r -o name,property,value,source redundant_metadata tank
NAME                 PROPERTY           VALUE  SOURCE
tank                 redundant_metadata all    default
tank/home            redundant_metadata all    inherited from tank
tank/registry         redundant_metadata none   local
tank/registry/blobs   redundant_metadata none   inherited from tank/registry

Інтерпретація: Шукайте локальні переоприділення, які могли бути встановлені як швидке рішення або оптимізація. «default» або «inherited» не означає автоматично правильне; це просто означає, що ніхто не змінював це.

Завдання 2: Безпечно змінити redundant_metadata для одного dataset

cr0x@server:~$ sudo zfs set redundant_metadata=all tank/registry
cr0x@server:~$ zfs get redundant_metadata tank/registry
NAME           PROPERTY           VALUE  SOURCE
tank/registry  redundant_metadata all    local

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

Завдання 3: Перевірити стан пулу й чи вже є помилки

cr0x@server:~$ zpool status -v tank
  pool: tank
 state: ONLINE
status: One or more devices has experienced an unrecoverable error.
action: Determine if the device needs to be replaced, and clear the errors
  see: none
config:

        NAME           STATE     READ WRITE CKSUM
        tank           ONLINE       0     0     0
          raidz2-0     ONLINE       0     0     0
            sda        ONLINE       0     0    12
            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

errors: Permanent errors have been detected in the following files:

        tank/registry@daily-2025-12-01:/blobs/sha256/aa/...

Інтерпретація: Помилки контрольної суми на пристрої — це не «окей, бо RAIDZ2». Вони — симптом. Постійні помилки, що вказують на шлях snapshot-а, часто позначають проблеми з метаданими або блоками, на які посилається той snapshot, що впливає на перегляд цього snapshot-а.

Завдання 4: Запустити scrub цілеспрямовано, а не з суєти

cr0x@server:~$ sudo zpool scrub tank
cr0x@server:~$ zpool status tank
  pool: tank
 state: ONLINE
status: scrub in progress since Tue Dec 24 10:11:22 2025
        1.23T scanned at 510M/s, 420G issued at 173M/s, 8.11T total
        0B repaired, 5.18% done, 0:07:42 to go

Інтерпретація: «Scanned» проти «issued» має значення. Якщо issued значно менше, пул шукає/чергує або обмежений IOPS. Метаданеві пули часто показують сильний розрив.

Завдання 5: Перевірити тиск простору (бо це змінює все)

cr0x@server:~$ zpool list -o name,size,alloc,free,capacity,frag,health
NAME  SIZE  ALLOC  FREE  CAPACITY  FRAG  HEALTH
tank  10T   8.7T   1.3T  87%       52%   ONLINE

Інтерпретація: 87% заповнення і 52% фрагментації — це зона, де «малі випадкові записи метаданих» стають дорожчими. Якщо ви налаштовуєте надмірність метаданих на пулі з таким заповненням, планування ємності — частина вирішення.

Завдання 6: Виявити набори даних, що важать метаданими, за кількістю об’єктів і логічним простором

cr0x@server:~$ zfs list -o name,used,refer,logicalused,logicalrefer,compressratio -r tank
NAME           USED  REFER  LOGICALUSED  LOGICALREFER  RATIO
tank           8.7T  128K   11.2T        128K          1.28x
tank/home      1.2T  1.2T   1.3T         1.2T          1.09x
tank/registry  6.8T  6.8T   9.4T         9.4T          1.38x

Інтерпретація: Це безпосередньо не показує метадані, але допомагає знайти dataset-и, де логічна проти фізичної поведінки і churn можуть вказувати на інтенсивну активність з вказівниками блоків. Комбінуйте з кількістю snapshot-ів і знанням навантаження.

Завдання 7: Порахувати snapshot-и і зрозуміти ризик збереження

cr0x@server:~$ zfs list -t snapshot -o name,used,refer,creation -r tank/registry | head
NAME                                USED  REFER  CREATION
tank/registry@hourly-2025-12-24-09   0B    6.8T   Tue Dec 24 09:00 2025
tank/registry@hourly-2025-12-24-08   0B    6.8T   Tue Dec 24 08:00 2025
tank/registry@daily-2025-12-23       12G   6.7T   Mon Dec 23 00:10 2025

Інтерпретація: Багато snapshot-ів — багато історичних шляхів метаданих. Якщо операції зі старими snapshot-ами падають, redundant metadata може стати частиною стратегії стійкості, але вам також потрібні регулярні scrub-и і розумне утримання.

Завдання 8: Підтвердити, чи існує special vdev (шар для метаданих)

cr0x@server:~$ zpool status tank | sed -n '1,80p'
  pool: tank
 state: ONLINE
config:

        NAME             STATE     READ WRITE CKSUM
        tank             ONLINE       0     0     0
          raidz2-0       ONLINE       0     0     0
            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
        special
          mirror-1       ONLINE       0     0     0
            nvme0n1p1    ONLINE       0     0     0
            nvme1n1p1    ONLINE       0     0     0

Інтерпретація: Якщо у вас є special vdev, він має бути надмірним. Якщо це один пристрій — ставтесь до нього як до очікуваної точки відмови.

Завдання 9: Перевірити куди йдуть метадані (високорівнева поведінка)

cr0x@server:~$ zpool get -o name,property,value,source feature@spacemap_histogram tank
NAME  PROPERTY                   VALUE  SOURCE
tank  feature@spacemap_histogram active local

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

Завдання 10: Спостерігати тиск I/O і латентність (швидкий огляд)

cr0x@server:~$ iostat -x 1 5
Linux 6.8.0 (server)  12/24/2025  _x86_64_  (32 CPU)

avg-cpu:  %user %nice %system %iowait  %steal   %idle
           6.12  0.00    3.45   18.90    0.00   71.53

Device            r/s     w/s   rkB/s   wkB/s  await  svctm  %util
sda              32.0   210.0   820.0  4600.0  98.12   3.10  79.2
sdb              30.0   208.0   800.0  4550.0 102.55   3.20  80.1
nvme0n1         900.0   700.0 72000.0 64000.0   1.20   0.05   8.5

Інтерпретація: Високий await на HDD при низькому пропуску часто вказує на насичення випадковим I/O — класична біль метаданих. Низьке завантаження NVMe special vdev свідчить, що воно не є вузьким місцем; високе — що шар метаданих перевантажений або неправильно розмірений.

Завдання 11: Спостерігати статистику I/O ZFS (рівень пулу)

cr0x@server:~$ zpool iostat -v tank 1 3
                               capacity     operations     bandwidth
pool                         alloc   free   read  write   read  write
---------------------------  -----  -----  -----  -----  -----  -----
tank                          8.7T   1.3T  2.10K  5.80K  180M   95M
  raidz2-0                    8.7T   1.3T  2.10K  5.80K  180M   95M
    sda                           -      -    350    970   30M   16M
    sdb                           -      -    350    970   30M   16M
    sdc                           -      -    350    970   30M   16M
    sdd                           -      -    350    970   30M   16M
    sde                           -      -    350    970   30M   16M
    sdf                           -      -    350    970   30M   16M
special                            -      -    900  1.10K  72M   64M
  mirror-1                         -      -    900  1.10K  72M   64M
    nvme0n1p1                      -      -    450    550   36M   32M
    nvme1n1p1                      -      -    450    550   36M   32M
---------------------------  -----  -----  -----  -----  -----  -----

Інтерпретація: Це допомагає підтвердити, чи трафік метаданих/малих блоків потрапляє на special vdev або чи HDD RAIDZ виконують болісну роботу. Якщо special vdev відсутнє, IOPS метаданих лягають на основні vdev-и.

Завдання 12: Перевірити dataset-параметри, що взаємодіють з поведінкою метаданих

cr0x@server:~$ zfs get -o name,property,value -s local,default recordsize,atime,xattr,dnodesize,compression,redundant_metadata tank/registry
NAME           PROPERTY           VALUE
tank/registry  recordsize         128K
tank/registry  atime              off
tank/registry  xattr              sa
tank/registry  dnodesize          legacy
tank/registry  compression        zstd
tank/registry  redundant_metadata all

Інтерпретація: Стратегія метаданих не живе сама по собі. xattr=sa може збільшити щільність метаданих у dnode; dnodesize впливає на те, скільки метаданих може жити «inline». Це може змінити обсяг I/O метаданих і вартість їх дублювання.

Завдання 13: Раннє виявлення помилок контрольних сум і очищення лише після виправлення

cr0x@server:~$ zpool status -x
pool 'tank' has experienced checksum errors
cr0x@server:~$ sudo zpool clear tank
cr0x@server:~$ zpool status -x
all pools are healthy

Інтерпретація: Очищати помилки — це для обліку після того, як ви усунули причину (замінили диск, виправили кабелі, завершили scrub). Очищати спочатку — просто видаляти докази і нічого не навчати систему.

Завдання 14: Використати контрольоване дерево файлів, щоб побачити витрати на метадані в мікрокосмі (лабораторна техніка)

cr0x@server:~$ mkdir -p /tank/testmeta
cr0x@server:~$ time bash -c 'for i in $(seq 1 200000); do echo x > /tank/testmeta/f_$i; done'
real    2m41.772s
user    0m20.118s
sys     1m39.332s

Інтерпретація: Це грубий інструмент, але робить витрати на метадані видимими. Повторіть на dataset-і з різними налаштуваннями redundant_metadata (у лабораторії) і порівняйте латентність та I/O-статистики. Не робіть цього в продакшні, якщо не любите пояснювати свої дії.

Швидкий план діагностики

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

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

cr0x@server:~$ zpool status -v tank

Дивіться на: помилки контрольної суми, деградовані пристрої, scrub в процесі, «permanent errors», повторні помилки читання на одному пристрої. Якщо ви бачите інкременти CKSUM, припускайте вплив на продуктивність, навіть якщо пул ONLINE.

Друге: чи ми обмежені ємністю/фрагментацією?

cr0x@server:~$ zpool list -o name,capacity,frag,alloc,free tank

Дивіться на: заповнення > 80–85% і високу фрагментацію. Якщо ви майже повні, накладні витрати дублювання метаданих більш імовірно зашкодять, і поведінка аллокатора може домінувати над усім.

Третє: це затримка IOPS (схоже на метадані) чи пропускна здатність (схоже на дані)?

cr0x@server:~$ iostat -x 1 10

Дивіться на: високий await з низьким KB/s вказує на тиск випадкового I/O — часто метадані. Високий KB/s з високою завантаженістю вказує на насичення послідовної пропускної здатності.

Четверте: чи special vdev робить свою роботу (якщо є)?

cr0x@server:~$ zpool status tank
cr0x@server:~$ zpool iostat -v tank 1 5

Дивіться на: special vdev завантажений, а HDD спокійні (добре: метадані відвантажені) проти HDD завантажені маленьким I/O (метадані застрягли на «іржі»).

П’яте: підтвердити налаштування dataset-ів на «гарячому» шляху

cr0x@server:~$ zfs get -o name,property,value,source redundant_metadata,copies,recordsize,xattr,dnodesize,primarycache tank/registry

Дивіться на: випадки, коли copies випадково встановлено в 2+ (поширений «ой»), або redundant_metadata встановлено непослідовно з навантаженням і ризиком.

Шосте: вирішити — виправляємо обладнання, навантаження чи конфігурацію?

Якщо є помилки: спочатку вирішуйте апаратні проблеми. Якщо майже повно: спочатку вирішуйте ємність. Якщо вузьке місце — IOPS метаданих: розгляньте special vdev (належно дзеркальний), зменшення churn-а метаданих (політика snapshot-ів, поведінка програми), і лише потім налаштовуйте політику метаданих.

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

Помилка 1: Ставитися до помилок контрольних сум як до «не термінових, бо надмірність»

Симптом: zpool status показує CKSUM помилки на пристрої, пул залишається ONLINE, але scrub-и сповільнюються і операції з метаданими стають спайковими.

Виправлення: Дослідіть і усуньте корінь проблеми (диск, кабель, HBA, бекплейн). Запустіть scrub після заміни. Лише після цього очищайте помилки.

Помилка 2: Використання redundant_metadata=none як універсальна оптимізація ємності

Симптом: Через місяці ви бачите постійні помилки, пов’язані з шляхами snapshot-ів або помилки обходу каталогу під час реплікації/очищення.

Виправлення: Перегляньте ризики. Розгляньте redundant_metadata=most або all для dataset-ів, що багато працюють з метаданими/критичних, особливо на RAIDZ. Поєднуйте з scrub-ами і розумним утриманням snapshot-ів.

Помилка 3: Плутати redundant_metadata з copies

Симптом: Пул «таємничо» заповнюється, латентність записів зростає, і ви знаходите copies=2 на великих dataset-ах.

Виправлення: Використайте zfs get copies по дереву і приберіть там, де це недоречно. Застосовуйте copies для вузько цільових випадків (маленькі критичні dataset-и на нерезервованих пулах або особливі сценарії), а не як повсякденний важіль надійності.

Помилка 4: Побудувати special vdev без надмірності

Симптом: Усе швидко, поки спеціальний пристрій не помре, і тоді пул у катастрофічному стані (часто неімпортований або відсутні критичні метадані).

Виправлення: Special vdev має бути дзеркальним (мінімум) і моніторитися як компонент першого класу. Трактуйте його як частину базового дизайну надмірності пулу.

Помилка 5: Очікувати негайні результати після зміни властивості

Симптом: Ви встановили redundant_metadata=all і не бачите змін у помилках або продуктивності, тож скасовуєте і оголошуєте його марним.

Виправлення: Пам’ятайте: воно впливає на нові записи. Користь накопичується, коли метадані переписуються. Ставте це як політику, а не як кнопку паніки.

Помилка 6: Ігнорувати заповнення пулу і фрагментацію під час налаштування метаданих

Симптом: Будь-яка зміна здається погіршенням, особливо на HDD RAIDZ пулах; латентність різко зростає під час snapshot-операцій і scrub-ів.

Виправлення: Поверніть ємність (видаліть дані, скоротіть збереження, додайте vdev). Налаштовувати на майже-повному пулі — як переставляти меблі у палаючому будинку: технічно можливо, емоційно шкідливо.

Контрольні списки / покроковий план

Контрольний список A: Вирішіть, що встановлювати (політика)

  1. Класифікуйте dataset-и за бізнес-важливістю: «можна відновити пізніше» проти «має бути онлайн».
  2. Класифікуйте за навантаженням: багато метаданих (малі файли, snapshot-и, каталоги) проти даних (великі послідовні файли).
  3. Класифікуйте за топологією vdev: mirror проти RAIDZ; і чи існує special vdev.
  4. Якщо RAIDZ + metadata-heavy + висока критичність: схильність до redundant_metadata=all (або хоча б most).
  5. Якщо mirror + здорове обладнання + не метаданево-важке: значення за замовчуванням може бути прийнятне; сконцентруйтесь на scrub-ах і моніторингу.
  6. Якщо пул >85% заповнений: вирішіть ємність перш ніж додавати накладні витрати.

Контрольний список B: Безпечне впровадження зміни

  1. Інвентаризація поточних налаштувань:
cr0x@server:~$ zfs get -r -o name,property,value,source redundant_metadata tank
  1. Виберіть один dataset на «гарячому» шляху і змініть його першим:
cr0x@server:~$ sudo zfs set redundant_metadata=all tank/registry
  1. Відстежуйте базову продуктивність до/після за допомогою статистик пулу і пристроїв:
cr0x@server:~$ zpool iostat -v tank 1 10
cr0x@server:~$ iostat -x 1 10
  1. Запустіть scrub у контрольному вікні і порівняйте виправлені помилки й пропускну здатність:
cr0x@server:~$ sudo zpool scrub tank
cr0x@server:~$ zpool status tank
  1. Розгортайте на інші dataset-и лише після розуміння накладних витрат.

Контрольний список C: Якщо підозрюєте вузьке місце IOPS метаданих

  1. Підтвердьте, що це латентність/IOPS, а не пропускна здатність (iostat -x).
  2. Підтвердьте, що пул не деградований / не реконструюється активно (zpool status -v).
  3. Перевірте ємність/фрагментацію (zpool list).
  4. Перевірте, чи існує special vdev і чи належно він розмірений і надмірний (zpool status).
  5. Лише потім налаштовуйте політику метаданих (redundant_metadata, утримання snapshot-ів та організацію dataset-ів).

FAQ

1) Чи завжди мені ставити redundant_metadata=all?

Ні. Це хороший дефолт для критичних, метаданево-важких dataset-ів на RAIDZ пулах, особливо з довгим утриманням snapshot-ів. На mirror-ах приріст цілісності зазвичай менший, і накладні витрати можуть не виправдатися для кожного dataset-а.

2) Чи є redundant_metadata заміною для mirror-ів або RAIDZ2?

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

3) У чому різниця між redundant_metadata і copies=2?

copies дублює й блоки даних також, що може бути надзвичайно дорогим у місці і навантаженні записів. redundant_metadata таргетує тільки метадані, зазвичай значно дешевше, і часто є більш прицільним інструментом.

4) Чи переписує зміна redundant_metadata існуючі метадані?

Не одразу. Воно впливає на ново-записані метадані. Існуючі блоки можуть бути переписані, коли файли змінюються, snapshot-и створюються/видаляються або блоки перерозподіляються з часом. Ставте це як політику на майбутнє.

5) Чи виправить це повідомлення «permanent errors have been detected»?

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

6) Чи робить special vdev redundant_metadata зайвим?

Ні. Special vdev покращує продуктивність метаданих і може підвищити стійкість, якщо він дзеркальний і здоровий. Але це все ще апарат, і він може мати корупцію чи помилки читання. Додаткові копії метаданих можуть доповнювати special vdev; вони не замінюють хорошого дизайну надмірності.

7) Які найпоширеніші ознаки, що метадані — це моє вузьке місце?

Високий I/O wait, високий диск await при низькому пропуску, повільні переліки каталогів, повільні операції зі snapshot-ами, повільні навантаження з малими файлами, і scrub «issued» значно нижче, ніж «scanned». Також: продуктивність погіршується з наповненням і фрагментацією пулу.

8) Чи може redundant_metadata погіршити продуктивність?

Так, особливо на HDD-пулах і при метаданево-важких навантаженнях. Ви додаєте додаткові малі записи. Якщо ви вже обмежені IOPS, це може підвищити латентність. Тому впроваджуйте по dataset-у і вимірюйте.

9) Якщо я на mirror-ах, чи варто ставити redundant_metadata=none для продуктивності?

Можливо, але не робіть це рефлекторно. Mirrors вже дають сильне самовиліковування, тож приріст цілісності менший; однак накладні витрати дублювання метаданих також можуть бути меншими, ніж ви думаєте для конкретного навантаження. Тестуйте на репрезентативному dataset-і і не оптимізуйте безпечність, якщо ви не впевнені у прийнятому режимі відмови.

10) Яка найменш ризикована «нудна правильна» конфігурація?

Для критичних dataset-ів: плануйте scrub-и регулярно, тримайте заповнення пулу під контролем, використовуйте надмірні vdev-и (mirror або адекватний RAIDZ), і свідомо встановлюйте стратегію метаданих (часто redundant_metadata=all для метаданево-важких RAIDZ dataset-ів). Більшість катастроф — це купа малих рішень «ми виправимо потім».

Висновок

redundant_metadata — один із тих важелів ZFS, що здається чекбоксом, поки ви не переживете інцидент, пов’язаний із метаданими. Тоді він починає виглядати як страховка з премією, що сплачується малими блоковими записами й накладними витратами на простір. Трюк — купувати цю страховку там, де вона має сенс: dataset-и з великим churn-ом метаданих, довгою історією snapshot-ів і високим бізнес-імпактом — особливо на RAIDZ пулах, де реконструкція під навантаженням дорога.

Якщо ви візьмете лише один операційний урок: не дискутуйте про надмірність метаданих абстрактно. Виміряйте стан пулу, ємність і IOPS-головне; зрозумійте, чи метадані на критичному шляху; і тоді свідомо встановлюйте redundant_metadata по dataset-у. ZFS зробить підрахунки, але не розставить пріоритети за вас.

← Попередня
Контейнери Docker лише для читання: підвищуйте безпеку, не ламаючи додаток
Наступна →
Proxmox «Не завантажувальний диск»: порядок завантаження BIOS/UEFI, прапори диска та швидкий шлях відновлення

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