Деякі відмови починаються не з виходу диска або паніки ядра. Вони починаються з набору даних із іменем data2, точки монтування, що «виглядала нормально», і доброго наміру адміністратора, який припустив, що він у правильному місці.
ZFS надзвичайно терплячий — поки ні. Імена в ZFS працюють як клей: вони пов’язують точки монтування, властивості, снапшоти, квоути, делегування, реплікацію, моніторинг і людську пам’ять. Якщо ви іменуєте набори даних як загальний ящик, ви будете відлагоджувати як із пов’язкою на очах. Якщо ви іменуєте їх так, ніби керуєте продакшеном, ви економитимете години щомісяця і іноді запобіжите дуже дорогому вечору.
Що насправді роблять імена наборів даних у ZFS
Ім’я набору даних ZFS виглядає як шлях — і це не випадковість. Це ієрархічний простір імен: pool/app/prod/postgres. Слеші мають семантику. Це ім’я також ідентифікатор, який використовують інструменти (zfs, zpool, задачі реплікації, програмне забезпечення для бекапів, моніторинг, маршрутизація алертів, делегування доступу). Ви не просто «позначаєте» набір даних; ви створюєте дескриптор, яким система користуватиметься назавжди.
У більшості стеків зберігання іменування косметичне. У ZFS ім’я впливає на:
- Спадкування властивостей: compression, recordsize, atime, sync, xattr, acltype, quotas/reservations. Ієрархія батько/дитина — спосіб моделювати поведінку за замовчуванням і винятки.
- Поведінку монтування:
mountpoint,canmount,sharenfs/sharesmbі неявне монтування під час завантаження. - Ідентичність снапшота: снапшоти адресуються як
dataset@snap. Ваш вибір імен визначає, чи може автоматизація знайти й оперувати правильним набором снапшотів. - Обсяг реплікації:
zfs send pool/app/prod@x | zfs receive backup/app/prod— це твердження про ієрархію й вибір. Іменування впливає на те, що можна безпечно реплікувати, виключати або перенаправляти. - Делегування та мультиорендарність:
zfs allowпрацює з іменами наборів даних. Чіткі межі важливі при делегуванні прав на снапшоти чи монтування. - Швидкість реагування на інциденти: під тиском люди впізнають шаблони. Зрозумілі імена скорочують «я думаю, це набір даних» до «це очевидно потрібний набір даних».
Імена дешеві. Перейменування — ні. Так, zfs rename існує і часто безпечний. Але зона ураження включає монтування, експорти, fstab‑подібні зв’язки, моніторинг, цілі бекапів, реплікаційні букмарки та все інше, що ваша організація підв’язала до старого імені. Найдешевший час бути послідовним — до першого графіка снапшотів у продакшені.
Опінійоване правило: іменуйте набори даних для операцій, а не під вашу внутрішню організаційну структуру. Команди та продукти змінюються. Точки монтування й контракти реплікації мають тенденцію застрявати, як жувальна гумка на підошві.
Нудна конвенція іменування, яка справді працює
Ось конвенція, що масштабується від «одної коробки в шафі» до «багатосайтової реплікації з вимогами зберігання», без перетворення на хобі‑таксономію.
Формат
Використовуйте таку форму:
<pool>/<scope>/<env>/<service>/<role>
Приклади:
tank/app/prod/postgres/datatank/app/prod/postgres/waltank/app/stage/api/logstank/shared/prod/hometank/infra/prod/monitoring/tsdb
Що означає кожен сегмент:
- pool: фізичне (або близьке до фізичного) домен відмов. Не намагайтеся кодувати «швидко/повільно» в іменах наборів даних; використовуйте пули або класи vdev для цього навмисно.
- scope: груба операційна межа (поширені:
app,infra,shared,backup,scratch). Це запобігає «все підdata». - env:
prod,stage,dev, можливоdr. Так, навіть на однохостових системах. Це змушує розміщувати налаштування за замовчуванням у правильному місці. - service: те, за що вас можуть запінгувати. Тримайте стабільним.
- role: лише коли потрібно, щоб розділити профілі властивостей (наприклад WAL vs data, logs vs uploads, cache vs durable).
Правила символів (навмисно нудно)
- Малі літери ASCII. Дозволені цифри.
- Використовуйте дефіси між словами, не підкреслення. Визначте один стиль і дотримуйтеся його; я обираю дефіси, бо це узгоджується з багатьма схемами в опсах.
- Без пробілів. Без «милої» пунктуації. Уникайте крапок, якщо немає вагомої причини.
- Тримайте сегменти короткими, але змістовними:
monitoringкраще, ніжmon, коли ви повернетеся через шість місяців.
Чому не вбудовувати все підряд? Бо в кінці ви закодируєте: підрозділ бізнесу, код проєкту, центр витрат, номер тікету й фази Місяця. Імена ZFS — це операційні ідентифікатори, а не схема бази даних. Помістіть метадані в теги в CMDB, в IaC або хоча б в zfs set org:* користувацькі властивості — про це пізніше.
Цитата, яку варто повісити над терміналом (перефразовано): Джин Кранс, директор польотів: «Будьте жорсткими й компетентними». Конвенції іменування — це частина компетентності.
Жарт №1: Іменування наборів даних схоже на чищення зубною ниткою: усі погоджуються, що корисно, і майже всі починають після першого болючого інциденту.
Проєктування ієрархії: різати там, де змінюються властивості
Ієрархія наборів даних — це не «папки в ZFS». Це дерево спадкування з прикріпленими точками монтування. Найкраща ієрархія — та, де кожна вершина представляє значущий політичний (policy) кордон: compression, recordsize, quota, reservation, sync‑поведінка, розклад снапшотів, збереження, шифрування і цілі реплікації.
Принцип проєктування: один набір даних на профіль властивостей
Якщо два шляхи потребують різних налаштувань — їм потрібні різні набори даних. Це не означає тисячі наборів; це означає, що ви проводите кордони там, де значення за замовчуванням перестають бути безпечними.
Поширені кордони, які заслуговують на окремі набори даних:
- Дані БД проти WAL/журнала: різні шаблони запису, часто різний
recordsize, інодіlogbias. - Зображення віртуальних машин: великі блоки, часті снапшоти, можливий
volblocksizeдля zvol, обережно зcompression. - Логи: у багатьох організаціях не варто їх снапшотити; окремий набір даних дозволяє виключити їх з реплікації та збереження.
- Завантаження користувачів: межі квот, часто потрібні снапшоти, компресія часто корисна.
- Кеші: встановіть
com.sun:auto-snapshot=falseабо подібний користувацький прапор для вашого інструментарію.
Принцип проєктування: надрівні — це політичні налаштування за замовчуванням
Створіть батьківський набір даних для кожного стабільного набору політик, задайте там властивості і дозвольте спадкування. Наприклад:
tank/app/prod: compression увімкнено, atime вимкнено, snapdir приховано, вибір нормалізації.tank/app/prod/postgres: тег розкладу снапшотів, тег групи реплікації.tank/app/prod/postgres/dataі.../wal: recordsize/logbias налаштовані під роль.
Чому це важливо: під час інциденту ви хочете відповісти на питання «яка політика тут застосовується?» одним запитом. Розумне дерево робить відповідь очевидною. Безладне дерево перетворює це на археологію.
Межі шифрування: називайте їх, щоб люди не дешифрували не те
Якщо ви використовуєте нативне шифрування ZFS, корені шифрування (набори даних, де encryption=on і зберігаються ключі) мають бути очевидні в іменуванні. Життєвий цикл ключів — це операційна межа така ж реальна, як VLAN.
Патерни, що працюють:
tank/secure/prod/hr/..., деtank/secure/prod— корінь шифрування.- Або суфікс:
.../encтільки якщо ви послідовні й це відповідає реальним межам ключів.
Патерни, що відпадають:
- Випадкові зашифровані набори даних, розкидані під незашифрованими батьками з іменами, що не вказують, де ключі або межі.
Іменування наборів даних — це те, як ви запобігаєте ситуації «просто змонтуйте» до «чому запит ключа з’явився на невірному хості о 2-й ночі».
Точки монтування, canmount і пастка «куди поділися мої файли»
Точки монтування ZFS потужні тим, що вони автоматичні. Вони також небезпечні тим самим.
Вирівнюйте імена наборів даних із точками монтування (в більшості випадків)
Найчистіша схема:
- Ім’я набору даних співпадає зі шляхом точки монтування та має ту саму ієрархію.
- Приклад:
tank/app/prod/postgres/dataмонтується в/srv/app/prod/postgres/data.
Це не обов’язково, але операційно корисно. Коли точка монтування відповідає дереву наборів даних, ви можете вивести одне з іншого. У стресовій ситуації це — золото.
Використовуйте canmount=off для «організаційних» наборів даних
Багато наборів даних існують, щоб нести успадковані властивості і не монтуватися. Їх слід робити не монтуваними за замовчуванням:
tank/app,tank/app/prod,tank/app/prod/postgresчасто хочутьcanmount=offізmountpoint, який або успадковується, або встановлений, але не монтується безпосередньо.
Якщо цього не робити, врешті-решт ви змонтуєте батьківський набір даних поверх дерев’яних точок монтування дітей, приховаєте дочірні набори і заплутаєте всіх. Так ви «втратите» дані, які все ще на диску — просто невидимі за шляхом, який ви очікували.
Коли іменування ламає монтування
Більшість помилок у іменуванні проявляються як помилки монтування:
- Набори даних створені під неправильним батьком (застосована невірна політика, успадкувався неправильний mountpoint).
- Точки монтування вручну встановлені хаотично і більше не відповідають ієрархії.
- Клони створені й змонтовані в якомусь «тимчасовому» місці, що стало постійним.
Жарт №2: ZFS із задоволенням змонтує ваш набір даних поверх теки з вашими нотатками про те, як цього не робити.
Снапшоти та реплікація: іменування як API автоматизації
На практиці іменування наборів даних стає API для вашої автоматизації. Роботи бекапу вибирають набори даних за префіксом. Правила реплікації відображають префікс джерела в префікс призначення. Політики збереження прив’язані до груп наборів даних. Якщо ви невпорядковано іменуєте, ваша автоматизація має ставати «розумною». «Розумна» автоматизація — місце, де ховаються баги.
Іменування снапшотів: робіть їх передбачуваними, сортуваними й придатними для grep
Снапшоти іменуються на рівні набору даних. Конвенція, що заспокоює людей і скрипти:
- Префікс за системою:
auto-,replica-,pre-upgrade- - Включіть час у форматі ISO‑подібному:
YYYYMMDD-HHMM - Опційно додайте клас збереження:
hourly,daily,weekly
Приклади імен снапшотів:
auto-hourly-20251226-0300auto-daily-20251226-0000pre-upgrade-20251226-1452
Чого уникати:
- Пробілів і локалізованих штампів часу (
Dec-26,26-12-2025) - Імен, які розуміє лише людина (
before-change) без мітки часу - Перенавантаження семантики в імені снапшоту («це також ID тикету й ім’я інженера»)
Відображення реплікації: імена повинні дозволяти зворотні трансформації
Найкращі налаштування реплікації — ті, де ім’я призначення є визначеним перетворенням імені джерела. Приклад:
- Джерело:
tank/app/prod/postgres - Призначення:
backup/app/prod/postgres
Це дозволяє міркувати про відновлення, тестування й аудит простими правилами. Також це запобігає «звідки цей набір даних?» детективній роботі.
Використовуйте користувацькі властивості для автоматизації, а не іменні хаки
ZFS підтримує користувацькі властивості (часто записуються як org:* або com.example:*). Вони успадковуються як і нативні властивості. Це ідеально для позначення наборів даних для розкладу снапшотів, груп реплікації та рівнів моніторингу — без кодування цього в імені.
Приклади:
org:backup=goldorg:owner=paymentsorg:rpo=15morg:pii=true
Імена кажуть «що це». Властивості кажуть «як ми це обробляємо». Не плутайте їх.
Цікаві факти та історичний контекст (бо іменування не стало дивним випадково)
- Імена наборів даних ZFS передували сучасним «тегам у хмарі». Ранні ZFS‑команди покладалися на іменування, бо користувацькі властивості й зовнішні практики метаданих ще не були звичними в опс‑робочих процесах.
- Простір імен наборів даних спроєктовано як дерево файлової системи, але модель спадкування робить його ближчим до дерева політик, ніж простого переліку директорій.
- Solaris ZFS популяризував ідею «адміністративних меж» через набори даних, задовго до того, як більшість Linux‑адмінів мали подібні примітиви за замовчуванням.
- Снапшоти — першокласні й дешеві, тож імена стають індексом до історії. Якщо ви не можете швидко знайти потрібний снапшот, «дешево» перетворюється на «дорого».
- zfs send/receive підштовхнув іменування у дизайн бекапів, бо цілі реплікації ідентифікуються іменами наборів даних, а не непрозорими ID.
- Спадкування властивостей — причина, чому ZFS уникає глобальних конфігурацій для багатьох поведінок. Це переміщує складність у дерево наборів даних — ваше іменування ним управляє.
- Багато сторонніх інструментів для снапшотів прийняли префікси типу «auto-», перетворивши імена снапшотів на де‑факто API для скриптів збереження й реплікації.
- Поширення контейнерних платформ зробило «набір даних на орендаря» звичним, що підвищило цінність делегування (
zfs allow) і чистого іменування. - Нативне шифрування збільшило вартість недбалих ієрархій, бо кордони ключів — це кордони наборів даних, а кордони наборів даних виражені в іменах.
Три корпоративні міні-історії з полів іменування
1) Інцидент через хибні припущення: «Цей набір даних очевидно стенд»
Компанія мала один пул зберігання tank і кілька наборів даних: tank/db, tank/db2, tank/web, tank/tmp. Минулому адміну довелося піти, як це часто буває. Нові інженери успадкували систему та панель моніторингу, яка показувала лише зайнятість пулу.
Розгортання пішло не так, і відповідаючий вирішив відкотити зміни за допомогою снапшотів. Вони побачили tank/db і припустили, що це стенд, бо «стенд був менший». Вони відновили снапшот у клон, тимчасово змонтували та скопіювали файли назад. Здавалося, що все працює — база запустилась.
Потім служба підтримки отримала тікети. Дані були старішими, ніж мали б бути. Відкат застосували у продакшені, а не в стенді. Причина не в тому, що ZFS підвів; він чинив точно так, як йому наказали. Причина — ідентичність: ім’я набору даних не кодувало середовище, і не було надійного тега властивості, що пояснив би, з чим працюють.
Виправлення не було героїчним. Вони створили нову ієрархію: tank/app/prod/postgres і tank/app/stage/postgres, перемістили дані з плановим простоєм і додали властивості org:env і org:service. Відтоді люди могли одним поглядом на zfs list не робити ставки на вдачу.
2) Оптимізація, що відпалила назад: «Зекономимо час монтування, зрізавши дерево»
Інша організація керувала завантаженим кластером віртуалізації і вирішила, що їхнє дерево наборів даних «занадто глибоке». Хтось сказав, що менше наборів — менше накладних і швидше завантаження. Вони спростили дерево в пласку структуру: tank/vm-001, tank/vm-002 тощо. Логи, образи й тимчасові дані помістили як каталоги всередині кожного набору даних VM.
Спочатку виглядало охайно. Потім квоти стали хаосом. Деяким VM потрібні були жорсткі ліміти, інші — резервування, кілька потребували різного recordsize для БД. Вони намагалися латати ситуацію дисципліною робіт з директоріями, чого ZFS не забезпечує. Єдине, що це контролювало, було «пам’ятайте вести себе добре», що не є системою контролю.
Кульмінація настала під час налаштування реплікації. Вони хотіли реплікувати лише «стійкі» дані, не тимчасові. У пласкій моделі тимчасові та стійкі дані жили в одному наборі, тож доводилося або реплікувати все, або нічого. Вони реплікували все, щоб відповідати RPO, що збільшило використання каналу й подовжило вікно реплікації. Потім це вікно наклалося на нічну обрізку збереження снапшотів, і відправлення почали періодично падати.
Вони не повернулися до початкового дерева; вони зробили краще. VM стали підлеглими під середовище і область кластера, а тимчасові/логи отримали власні набори даних з прапорами виключення з автоматичних снапшотів. Та «оптимізація» не дала переваг у продуктивності; це була політична помилка під виглядом спрощення.
3) Нудно, але правильно: префіксна селекція й чиста межа врятували день
Фінансова компанія мала суворе правило іменування: все, що впливає на клієнтів, перебувало під tank/app/prod. Усе інше — артефакти збірки, кеші, тестові відновлення — під tank/scratch або tank/app/dev. Люди жалілися, що це бюрократія. Вона була. І вона працювала.
Під час інциденту з дисковим простором латентність зросла, і пул заповнився швидше, ніж очікували. Команді потрібно було звільнити місце, не граючи в рулетку з видаленнями. Оскільки дерево мало чисті межі, вони змогли спершу цільово видалити низьковартісні набори: знищили старі клони й снапшоти під tank/scratch і підтвердили, що tank/app/prod залишився недоторканим.
Потім вони проаналізували зростання снапшотів. Іменування дозволило швидко побачити, яка служба генерує найбільші дельти, бо все було згруповано під tank/app/prod/<service>. Вони могли обмежити «порушника» й утримати систему стабільною.
Ніхто не отримав підвищення за це. Ніхто не писав постмортем під назвою «Наша конвенція іменування врятувала продакшен». Але відсутність хаосу — це і була суть. Нудно працює.
Практичні завдання: команди, виводи, що це означає, та рішення
Це реальні завдання, які ви виконуватимете при побудові конвенції іменування, аудиті існуючої або відлагодженні о 02:17 з кавою, що підштовхує до рішень.
Завдання 1: Перелік наборів даних з точками монтування, щоб виявити дрейф імен→шляхів
cr0x@server:~$ zfs list -o name,mountpoint,canmount -r tank/app/prod
NAME MOUNTPOINT CANMOUNT
tank/app/prod /srv/app/prod off
tank/app/prod/postgres /srv/app/prod/postgres off
tank/app/prod/postgres/data /srv/app/prod/postgres/data on
tank/app/prod/postgres/wal /srv/app/prod/postgres/wal on
Що це означає: Батьки несуть політику (canmount=off), діти монтуються там, де очікується, і точки монтування віддзеркалюють ієрархію наборів даних.
Рішення: Якщо ви бачите набір даних, змонтований у непов’язаному місці (наприклад, /var/lib/postgresql, тоді як ім’я натякає на /srv), вирішіть, вирівнювати точки монтування або перейменувати набори даних, щоб люди перестали гадати.
Завдання 2: Показати успадковані властивості, щоб підтвердити кордони політик
cr0x@server:~$ zfs get -o name,property,value,source -r compression,atime,recordsize tank/app/prod/postgres
NAME PROPERTY VALUE SOURCE
tank/app/prod/postgres compression lz4 inherited from tank/app/prod
tank/app/prod/postgres atime off inherited from tank/app/prod
tank/app/prod/postgres recordsize 128K default
tank/app/prod/postgres/data recordsize 16K local
tank/app/prod/postgres/wal recordsize 128K default
Що це означає: Значення за замовчуванням беруться з tank/app/prod, а data налаштовано локально. Іменування підказує, чому data існує як окремий набір даних.
Рішення: Якщо ви знаходите багато локальних переозначень властивостей на випадкових наборах даних, ймовірно, потрібно додати проміжні батьківські набори даних для спільних політик — потім перейменувати або реорганізувати відповідно.
Завдання 3: Знайти «таємні» набори даних, що не підходять під конвенцію
cr0x@server:~$ zfs list -H -o name | egrep -v '^(tank/(app|infra|shared|backup|scratch)/)'
tank/data
tank/db2
tank/oldstuff
Що це означає: Ці набори даних не належать до жодної визнаної області (scope).
Рішення: Розслідуйте кожен: якщо це продакшен — мігруйте/перейменуйте у конвенцію; якщо застаріле — плануйте видалення; якщо невідоме — помістіть у карантин, встановивши readonly=on тимчасово, доки не знайдете власника.
Завдання 4: Відобразити імена наборів даних на фактичні змонтовані файлові системи
cr0x@server:~$ mount -t zfs | head
tank/app/prod/postgres/data on /srv/app/prod/postgres/data type zfs (rw,xattr,posixacl)
tank/app/prod/postgres/wal on /srv/app/prod/postgres/wal type zfs (rw,xattr,posixacl)
tank/shared/prod/home on /home type zfs (rw,xattr,posixacl)
Що це означає: Ви швидко бачите, чи щось змонтовано там, де «не повинно» (наприклад, змонтовано на / або ненавмисно поверх /var).
Рішення: Якщо набір даних змонтовано поверх критичної теки несподівано, поводьтеся з цим як з інцидентом: перевірте, чи підлягає приховування вміст теки й чи батьківський набір було змонтовано випадково.
Завдання 5: Підтвердити, що ви не приховуєте дочірні набори даних випадково змонтованим батьком
cr0x@server:~$ zfs get -o name,property,value,source canmount,mountpoint tank/app/prod
NAME PROPERTY VALUE SOURCE
tank/app/prod canmount off local
tank/app/prod mountpoint /srv/app/prod local
Що це означає: canmount=off завадить цьому набору даних монтуватися і затуляти своїх дітей.
Рішення: Якщо у організаційних батьків canmount=on, встановіть off, якщо немає дуже зваженої причини. Потім перемонтуйте і перевірте видимість.
Завдання 6: Аудит сповзань снапшотів за префіксом набору даних (іменування тут окупається)
cr0x@server:~$ zfs list -t snapshot -o name,used,creation -s creation | tail -5
tank/app/prod/postgres/data@auto-hourly-20251226-0200 312M Fri Dec 26 02:00 2025
tank/app/prod/postgres/data@auto-hourly-20251226-0300 298M Fri Dec 26 03:00 2025
tank/app/prod/postgres/wal@auto-hourly-20251226-0200 28M Fri Dec 26 02:00 2025
tank/app/prod/postgres/wal@auto-hourly-20251226-0300 31M Fri Dec 26 03:00 2025
tank/app/prod/postgres/data@pre-upgrade-20251226-0322 1M Fri Dec 26 03:22 2025
Що це означає: Ви бачите дельти по наборах даних і чи послідовне іменування снапшотів. Імена снапшотів добре сортуються і сигналізують про наміри.
Рішення: Якщо ви бачите несподівані великі дельти снапшотів під набором даних, ім’я якого вказує на «логи» або «кеш», розділіть його на окремі набори даних і виключіть шумні з політик снапшотів/реплікації.
Завдання 7: Ідентифікувати набори даних, які не слід снапшотити (й довести це)
cr0x@server:~$ zfs get -r -o name,property,value org:auto-snapshot tank/app/prod
NAME PROPERTY VALUE SOURCE
tank/app/prod org:auto-snapshot true local
tank/app/prod/postgres org:auto-snapshot true inherited from tank/app/prod
tank/app/prod/postgres/data org:auto-snapshot true inherited from tank/app/prod
tank/app/prod/api/logs org:auto-snapshot false local
Що це означає: Ви використовуєте користувацькі властивості для маркування придатності до автоматичних снапшотів, і можна перевизначити це на листових наборах даних чисто.
Рішення: Якщо ви кодуєте «nosnap» в імені набору даних — припиніть. Використовуйте користувацькі властивості, щоб змінювати політику без перейменування активів.
Завдання 8: Знайти споживачів простору за набором даних і вирішити, чи відповідає ім’я
cr0x@server:~$ zfs list -o name,used,refer,compressratio -s used | tail
tank/app/prod/postgres/data 1.21T 1.19T 1.62x
tank/app/prod/vm/images 1.44T 1.40T 1.08x
tank/shared/prod/home 1.88T 1.75T 1.37x
Що це означає: Ви бачите, які набори даних споживають простір, а коефіцієнти стиснення дають підказки щодо вмісту.
Рішення: Якщо vm/images величезний і мало стискається — це може бути нормально; якщо logs величезний і має снапшоти — це запах дизайну: розділіть і відрегулюйте політику.
Завдання 9: Перевірити квоти й резервації (іменування має робити це очевидним)
cr0x@server:~$ zfs get -o name,property,value,source quota,reservation tank/app/prod/api
NAME PROPERTY VALUE SOURCE
tank/app/prod/api quota 500G local
tank/app/prod/api reservation none default
Що це означає: Цей набір даних має жорстку квоту. Якщо він заповниться, служба відпаде — передбачувано.
Рішення: Якщо у вас є квоти, ім’я набору даних має відображати межу (на сервіс, на орендаря, на роль). Якщо квоти стоять на неясному наборі типу tank/data, ви ризикуєте несподіваними відмовами.
Завдання 10: З’ясувати, хто «володіє» набором даних (не вгадуючи по імені)
cr0x@server:~$ zfs get -o name,property,value -s local,inherited -r org:owner,org:service,org:env tank/app/prod/postgres
NAME PROPERTY VALUE
tank/app/prod/postgres org:owner payments
tank/app/prod/postgres org:service postgres
tank/app/prod/postgres org:env prod
tank/app/prod/postgres/data org:owner payments
tank/app/prod/postgres/data org:service postgres
tank/app/prod/postgres/data org:env prod
Що це означає: Власність і середовище — явні метадані, а не племінні знання.
Рішення: Якщо ви не можете відповісти «кого треба оповістити з цього набору даних» з властивостей, виправте це. Імена самі по собі не є стабільною організаційною структурою.
Завдання 11: Безпечно перейменувати набір даних (і перевірити, що зміниться)
cr0x@server:~$ sudo zfs rename tank/db2 tank/app/prod/postgres
cr0x@server:~$ zfs list -o name,mountpoint tank/app/prod/postgres
NAME MOUNTPOINT
tank/app/prod/postgres /srv/app/prod/postgres
Що це означає: Ідентичність набору даних змінилася, і якщо точки монтування успадковані або встановлені продумано, воно опиняється там, де очікується.
Рішення: Перед перейменуванням у продакшені інвентаризуйте залежності: скрипти бекапів, цілі реплікації, правила моніторингу, експорти, конфіги контейнерів. Якщо ви не можете інвентаризувати — ви не готові до перейменування; створіть новий набір даних і перемістіть дані.
Завдання 12: Планувати відображення реплікації за іменами і підтвердити наявність снапшотів
cr0x@server:~$ zfs list -t snapshot -o name -s creation -r tank/app/prod/postgres | tail -3
tank/app/prod/postgres/data@auto-hourly-20251226-0200
tank/app/prod/postgres/data@auto-hourly-20251226-0300
tank/app/prod/postgres/data@pre-upgrade-20251226-0322
cr0x@server:~$ sudo zfs send -R tank/app/prod/postgres@auto-hourly-20251226-0300 | sudo zfs receive -u backup/app/prod/postgres
Що це означає: -R реплікує піддерево. -u приймає без негайного монтування (добре для контрольованих переключень).
Рішення: Якщо у ваше піддерево входить сміття (логи, кеш), не реплікуйте його повністю. Розділіть набори даних так, щоб реплікація піддерева відповідала бізнес‑намірам. Іменування робить розділення очевидним і вибірковим.
Завдання 13: Виявити невідповідності регістру та нелегальну творчість
cr0x@server:~$ zfs list -H -o name | egrep '[A-Z ]'
tank/App/Prod/API
Що це означає: Хтось створив набір даних з сегментами у верхньому регістрі, що ламає конвенції і скрипти, які припускають малі літери.
Рішення: Перейменуйте на малі літери зараз. Чим довше чекати, тим більше «клей» закріпиться навколо помилки.
Завдання 14: Виявити «сніжинки» з локальними точками монтування, що кусають при відновленнях
cr0x@server:~$ zfs get -H -o name,value,source mountpoint -r tank | awk '$3 ~ /^local/ {print}'
tank/app/prod/postgres/data /var/lib/postgresql/data local
tank/shared/prod/home /home local
Що це означає: Ці набори даних мають локальні перевизначення mountpoint. Деякі нормальні (/home — навмисно); інші підозрілі (postgres/data монтується в /var, тоді як конвенція пропонує /srv).
Рішення: Вирішіть, чи ваша конвенція «імена віддзеркалюють точки монтування», чи «імена логічні, точки монтування — застарілі». Змішувати обидва без документації — шлях до відновлень, що монтуються не туди.
Плейбук швидкої діагностики: знайдіть вузьке місце швидко
Коли зберігання «повільне», часу милуватися деревом наборів даних немає. Потрібна коротка, безжальна послідовність, що дає діючу гіпотезу. Іменування важливе, бо звужує область пошуку.
Перше: це проблема на рівні пулу — ємність чи фрагментація?
cr0x@server:~$ zpool list
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 7.25T 6.91T 352G - - 52% 95% 1.00x ONLINE -
Інтерпретація: 95% заповнення і 52% фрагментації — вечірка латентності, куди вас не запрошували.
Рішення: Звільніть місце зараз (видаліть снапшоти/клони в низьковартісних областях, як scratch), або додайте ємність. Не налаштовуйте recordsize, коли пул задухається.
Друге: яке піддерево набору даних генерує записи і дельти снапшотів?
cr0x@server:~$ zfs list -o name,used,refer -r tank/app/prod | tail
tank/app/prod/api 220G 180G
tank/app/prod/postgres 1.24T 1.20T
tank/app/prod/vm 1.50T 1.45T
Інтерпретація: Топ‑споживачі очевидні. Гарне іменування означає, що ви знаєте, що ці рядки представляють, без роєння по директоріях.
Рішення: Сфокусуйте розслідування на топових наборах даних, а не на всьому пулі.
Третє: робоче навантаження прив’язане до sync, метаданих чи пропусків кеша читання?
cr0x@server:~$ zfs get -o name,property,value -r sync,recordsize,atime,primarycache tank/app/prod/postgres
NAME PROPERTY VALUE
tank/app/prod/postgres sync standard
tank/app/prod/postgres recordsize 128K
tank/app/prod/postgres atime off
tank/app/prod/postgres primarycache all
tank/app/prod/postgres/data recordsize 16K
Інтерпретація: Якщо сервіс чутливий до латентності запису і ви бачите високу латентність sync‑записів, перевіряйте SLOG, налаштування sync і поведінку fsync в застосунку. Якщо це читання і багато промахів кеша, перевіряйте розмір ARC і робочий набір.
Рішення: Вирішіть, чи це проблема властивостей (тонке налаштування на рівні набору даних), чи апаратна/пулова. Іменування допомагає, бо ролі на кшталт wal мають власний набір даних для таргетованого тюнінгу.
Четверте: перевірте правильність монтувань перед тим, як звинувачувати диски
cr0x@server:~$ zfs list -o name,mountpoint,canmount -r tank/app/prod/postgres
NAME MOUNTPOINT CANMOUNT
tank/app/prod/postgres /srv/app/prod/postgres off
tank/app/prod/postgres/data /srv/app/prod/postgres/data on
tank/app/prod/postgres/wal /srv/app/prod/postgres/wal on
Інтерпретація: Якщо щось змонтовано неправильно, ви можете побачити «проблеми з продуктивністю», що фактично є «ви пишете у кореневу файлову систему, а не в ZFS» або «ви пишете в приховану теку під монтуванням».
Рішення: Виправте монтування спочатку. Потім заміряйте продуктивність знову. Половина інцидентів зі зберіганням — це інциденти ідентичності шляху.
Типові помилки: симптом → причина → виправлення
1) Симптом: «Мої файли зникли після перезавантаження»
Причина: Батьківський набір даних змонтований поверх теки, яка раніше містила файли (або поверх дочірніх точок монтування), приховуючи вміст. Часто через canmount=on у організаційних наборах даних.
Виправлення: Встановіть canmount=off на батьках, упевніться, що листові набори даних мають правильні mountpoint, і перевірте приховані файли, тимчасово відмонтуючи та інспектуючи підлягаючу теку.
2) Симптом: Снапшоти величезні і вікна реплікації постійно пропускають терміни
Причина: Логи/кеш/тимчасові дані поділяють набір даних зі стійкими даними, тож снапшоти захоплюють велику кількість змін. Іменування часто це видає: tank/app/prod/api містить logs/ та cache/ як директорії.
Виправлення: Розділіть на .../data, .../logs, .../cache набори даних. Виключіть логи/кеш з політик снапшотів і реплікації через користувацькі властивості.
3) Симптом: Квота вдаряє не ту команду
Причина: Квоти встановлено на наборі даних, що не відображає реальної межі власності (наприклад tank/shared), або неоднозначне іменування заохочує змішане використання.
Виправлення: Реорганізуйте, щоб кожен орендар/сервіс мав набір даних з чіткою назвою і явним org:owner. Застосовуйте квоти там, а не на загальному шарі.
4) Симптом: Бекапи пропускають сервіс після перейменування
Причина: Відбір бекапів базується на жорстко вбудованих іменах, а перейменування зроблено без оновлення пайплайну. Або бекапи використовували фільтри префіксів, але нове ім’я змістилося за межі очікуваного префіксу.
Виправлення: Стандартизувати префікси (tank/app/prod) і вибирати за префіксом плюс користувацькі властивості (наприклад org:backup=gold). Розглядайте перейменування як подію, що потребує управління змінами з явною перевіркою залежностей.
5) Симптом: Реплікація приходить у хаотичну структуру призначення
Причина: Імена призначення не відображають імена джерела, тож receive‑операції потрапляють у дивні шляхи. Хтось зробив «швидке» receive у backup/incoming і не нормалізував.
Виправлення: Визначте детерміністичне правило відображення: tank/* → backup/* для стійких областей, і приймайте у стабільні цілі. Використовуйте zfs receive -u і встановлюйте mountpoint навмисно.
6) Симптом: «Чому цей набір даних має дивні властивості?»
Причина: Переозначення властивостей розкидані хаотично, бо ієрархія не має проміжних політичних вузлів. Іменування зазвичай це показує: непослідовна глибина, довільні групування сервісів.
Виправлення: Вставте проміжні набори даних, що представляють пакети політик (наприклад tank/app/prod, tank/app/prod/postgres). Перемістіть дітей під них і видаліть зайві локальні переозначення.
7) Симптом: Моніторинг і маршрутизація алертів непослідовні
Причина: Імена наборів даних не кодують стабільну ідентичність сервісу, і немає користувацьких властивостей для відображення на власників/середовища.
Виправлення: Наведіть порядок <scope>/<env>/<service> на початку імені та додайте org:owner, org:env, org:service властивості всюди. Моніторинг повинен читати їх, а не парсити випадкові рядки.
Чеклісти / покроковий план
Покроково: встановити конвенцію іменування без ламання продакшена
- Інвентаризація поточних наборів даних: перелік імен, точок монтування та ключових властивостей. Виявити аутлаєри та двозначні імена.
- Визначте верхньорівневі області (scopes): оберіть 3–6, що відповідають операційній реальності (
app,infra,shared,backup,scratch). - Визначте середовища: щонайменше
prodіnonprod(абоstage/dev, якщо ви ними користуєтесь). - Виберіть імена сервісів: стабільні, придатні для пейджингу ідентичності. Уникайте внутрішніх кодових назв проєктів.
- Вирішіть базу для точок монтування:
/srvпроти/var/libчи спадщина. Запишіть. Послідовність важливіша за ідеологію. - Створіть батьківські набори даних з
canmount=off: це ваші носії політик. - Встановіть політики за замовчуванням на правильному рівні: compression, atime, acltype/xattr, snapdir і ваші org‑властивості.
- Мігрируйте по одному сервісу: створюйте нові набори даних, rsync/copy, переключайте точки монтування, перевіряйте, потім виводьте старі набори з обігу.
- Оновіть автоматизацію: розклади снапшотів, реплікацію, моніторинг, правила відбору бекапів.
- Закріпіть правило: додайте перевірку передпольоту в provisioning/IaC, що відхиляє імена, які не відповідають правилам.
Чекліст: правила іменування для рев’ю
- Кожен продакшен‑набір даних знаходиться під
<pool>/app/prod(або ваш еквівалент). - Кожен сервіс має унікальне піддерево:
.../<service>. - Існують окремі набори даних там, де відрізняються властивості (DB data/WAL/logs/cache/uploads/VM images).
- Батьки, створені тільки для групування, мають
canmount=off. - Точки монтування або систематично вирівняні з іменами, або систематично задокументовані як винятки — ніколи «якось».
- Користувацькі властивості для
org:owner,org:env,org:serviceі для рівнів бекапу/реплікації. - Імена снапшотів слідують послідовній, сортованій часовій конвенції.
- Цілі реплікації віддзеркалюють імена джерела за детерміністичним правилом.
Чекліст: коли збираєтесь перейменувати набір даних
- Підтвердьте відсутність жорстко вбудованих посилань у бекапах та задачах реплікації.
- Підтвердьте, що моніторинг користується властивостями/префіксами, які й надалі відповідатимуть.
- Підтвердьте, що точки монтування й експорти будуть правильні після перейменування.
- План відкату: якщо перейменування створить проблеми, чи можна швидко перейменувати назад?
- Комунікуйте: імена наборів даних — це спільне API; розглядайте це як зміну інтерфейсу.
FAQ
1) Чи повинні імена наборів даних відповідати точкам монтування?
Ні. Але якщо ні — ви маєте бути послідовними й навмисними. У продакшені передбачуване відображення зменшує людські помилки. Якщо успадкували спадщинні mountpoint, тримайте імена логічними і відслідковуйте відображення через властивість mountpoint і документацію, а не на відчуттях.
2) Наскільки глибокою має бути моя ієрархія наборів даних?
Столько, скільки потрібно вашим політикам, і не глибше. Якщо властивості не відрізняються, окремий набір даних зазвичай зайвий. Якщо властивості відрізняються — не розділяти це технічний борг із відсотками.
3) Чи варто включати регіон/хост в ім’я набору даних?
Загалом — ні. Пул уже живе на хості, і цілі реплікації мають відображати імена між хостами. Регiон/хост — у системному інвентарі та імені пулу призначення, а не у шляху кожного набору даних.
4) А мультиорендні системи?
Використовуйте межу орендаря: tank/app/prod/<service>/tenants/<tenant-id> (або customers). Застосовуйте квоти й делегування на цій межі. Не заштовхуйте багато орендарів в один набір даних, якщо вони не мають однакового політичного стану.
5) Чи кодувати політику збереження в імені набору даних?
Ні. Кодуйте збереження в користувацьких властивостях (наприклад org:backup=gold, org:retention=daily-30) або в конфігу інструмента для снапшотів. Імена мають ідентифікувати навантаження; властивості — визначати обробку.
6) Чи нормально мати набори даних з іменами «data», «data2», «misc»?
У лабораторії — так. У продакшені — це відмова, що чекає на людину. Якщо потрібен catch‑all, назвіть його scratch і ставтеся до нього так, ніби його можна видалити без вибачень.
7) Чи можна безпечно перейменовувати набори даних у продакшені?
Технічно часто — так. Операційний ризик — це екосистема навколо імені. Якщо скрипти, моніторинг, експорти або цілі бекапів посилаються на старе ім’я — ви їх поламаєте. Перейменовуйте тільки коли можете проінвентаризувати залежності, або мігруйте шляхом створення нового набору даних та переміщення даних.
8) Як снапшоти впливають на стратегію іменування?
Снапшоти адресуються як dataset@snap, отже імена наборів даних і снапшотів формують комбінований ідентифікатор, який читають люди і інструменти. Вибирайте імена, читабельні в такій комбінованій формі і що сортуються за таймстемпом.
9) Який найшвидший виграш, якщо іменування вже безладне?
Створіть чисті верхньорівневі області і почніть розміщувати нові навантаження під ними. Потім поступово мігруйте найгірші випадки. Також додайте org:owner і org:env властивості всюди, щоб ви могли маршрутизувати алерти й приймати рішення без парсингу імен.
10) Краще мати один пул чи кілька, щоб виразити «рівні»?
Якщо рівні означають різне апаратне або домени відмов — використовуйте різні пули. Якщо рівні — просто різні політики на тому самому обладнанні — набори даних підходять. Не кодуйте рівні в іменах, коли підґрунтя зберігання фактично не відрізняється.
Висновок: наступні кроки, що працюють
Якщо ваші імена наборів даних наразі музей минулих рішень, не намагайтеся виправити все за один уїк‑енд. Виправляйте як SRE: поступово, з огорожами й з урахуванням наступного інциденту.
- Оберіть конвенцію і запишіть її у місці, де люди справді бачать її під час provisioning і рев’ю.
- Створіть батьківські політичні набори даних (
app/prod,app/stage,infra/prod,scratch) зcanmount=off. - Додайте користувацькі властивості для
org:owner,org:envіorg:service. Нехай автоматизація читає їх замість парсингу імен. - Виділіть один набір даних з високою частотою змін (логи/кеш) із стійкого набору і спостерігайте, як зменшується ріст снапшотів і скорочується час реплікації.
- Забезпечте дотримання в IaC або скриптах провізії: відхиляйте набори даних, що не відповідають правилам. Люди не пам’ятають; інструменти пам’ятають.
Хороше іменування не зробить ваші диски швидшими. Воно зробить ваші рішення швидшими — а в продакшені це майже те саме.