У вас є дані на ZFS-сервері, які новіші за призначення. Або джерело старіше й хитке, тоді як нова ціль суворо ставиться до фіч.
У будь-якому разі ваш перший “zfs send | zfs receive” виглядає впевнено — допоки о 2:00 ночі не впадає з повідомленням про помилку, яке схоже на плечима.
Ось реальність експлуатації: реплікація ZFS потужна, але не магічна. Send-потоки несуть припущення — про фічі датасету, feature flags пулу, режими шифрування
і навіть про те, чи розуміє ваша ціль діалект, яким ви говорите. Цей посібник допоможе перестати гадати.
Ментальна модель, яка передбачає відмови
Реплікація ZFS — це два окремі, накладені контрактні рівні:
-
Контракт пулу: чи може цільовий пул взагалі представляти on-disk структури, потрібні для стану датасету, що надходить?
Саме тут мають значення pool feature flags і “версії” ZFS. -
Контракт потоку: чи зрозумілий цілі формат send stream, і чи містить він типи записів, які отримувач може застосувати?
Тут підводять до невдачі “нові можливості send-потоку” і такі прапорці як-L,-c,-w,
-eабо--raw.
Ці контракти пов’язані, але не тотожні. Може бути так, що пул-ціль підтримує всі потрібні feature flags, але ви все одно провалитесь,
бо використали варіант потоку, який приймач не вміє парсити. Або навпаки: приймач розуміє потік, але пул-ціль не може безпечно активувати потрібну фічу.
Перестаньте думати у термінах «версій ZFS»
Люди питають: «Чи може ZFS 2.1 відправити в ZFS 0.8?» Таке питання зрозуміле і часто марне. В OpenZFS важливо те, що:
- pool feature flags (
zpool get all,zpool status,zpool get feature@*). - фічі та властивості датасету (шифрування, великі блоки, embedded data, redaction тощо).
- фічі потоку, які погодив приймач (що може прийняти
zfs receive). - що ви попросили
zfs sendзробити (raw vs decrypted, стиснення чи ні, рекурсивна реплікація, властивості).
Операційно сумісність — це перетин трьох сторін: можливостей пулу джерела, можливостей пулу призначення і обраного формату send-потоку.
Якщо хоча б один елемент «надто новий» для інших — реплікація зазнає невдачі. Або ще гірше: вона пройде, але змусить ухвалити рішення, про які ви не здогадувалися
(наприклад втратити шифрування або наслідкувати mountpoint, якого ви не хотіли в продакшні).
Парафраз ідеї від Jeff Bezos (про надійність і суміжне — і боляче правда для ops): «Будьте впертими в баченні, гнучкими в деталях.» Для реплікації ZFS
ваше бачення — цілісність даних. Деталі — це параметри потоку. Будьте гнучкі там.
Цікаві факти та історія, що важливі в продакшні
- Спочатку ZFS використовував «версії пулу» (одне ціле число). Сучасний OpenZFS перейшов на feature flags, щоб пули могли еволюціонувати без монолітного апдейту версії.
- Feature flags прив’язані до пулу, а не до хоста. Оновлення ОС не оновлює пул, поки ви явно не увімкнете фічі (часто через
zpool upgrade). - Коли фіча активна, зазвичай назад не повернешся. “Пониження” — це зазвичай “відновлення з реплікації в старіший пул”, а не зворотна операція на місці.
- Send-потоки можуть включати не лише блоки: властивості, снапшоти, клони й іноді припущення про mountpoint і holds.
- Зашифровані датасети змінили семантику реплікації. Raw-send зберігає шифрування і ключі лишаються на джерелі; non-raw send може мовчазно передати відкритий текст.
- Bookmarks існують, щоб зробити інкрементальну реплікацію надійнішою без зберігання старих снапшотів назавжди, але потрібна підтримка приймача і дисципліна в іменуванні.
- Стиснений send — не лише «стиснення на каналі». Залежно від прапорців і версій, він може нести вже стиснені блоки; добре для каналу, але плутає сумісність.
- Підтримка великих блоків — це не просто властивість. Вона взаємодіє з feature flags пулу і поведінкою приймача; невідповідність може викликати помилки receive, що виглядають як корупція.
- OpenZFS крос-платформний, але не ідеально однорідний. FreeBSD, illumos-спадкоємці і Linux загалом вирівнюються, але крайові фічі з’являються в різний час.
Жарт №1: дискусії про сумісність ZFS схожі на сімейні групові чати — усі клянуться, що говорять однією мовою, а ніхто не розуміє іншого.
Правила сумісності: що має збігатися, а що може відрізнятися
Правило 1: ціль має підтримувати всі on-disk фічі, потрібні для стану датасету
Якщо send-потік репрезентує стан датасету, що вимагає фічі, які цільовий пул не може увімкнути, receive зазнає невдачі. Це незаперечно.
Не має значення, наскільки ввічливі ваші прапорці send.
Ключова тонкість: пул може мати фічі «enabled», але не «active». “enabled” означає, що фіча доступна; “active” — що вона вже використовується в метаданих пулу.
Реплікація може спровокувати активацію, коли вона матеріалізує структури, які цього вимагають.
Правило 2: приймач має розуміти формат потоку, який ви генеруєте
Деякі покращення send-потоку чисто адитивні; старіші приймачі можуть зашипіти на незнайомі типи записів. Якщо ціль старіша, вважайте, що треба
тримати потік консервативним, доки не перевірили підтримку приймача.
Правило 3: шифрування множить складності сумісності
Зашифровані датасети — це місце, де «в лабораторії працювало» перетворюється на провал у продакшні. Критичне рішення — чи ви відправляєте:
- Raw зашифрований (зберігає шифрування, вимагає підтримки raw receive та фіч шифрування на приймачі).
- Розшифрований (дані прибувають у plaintext; може бути прийнятним для міграції у нову домен шифрування, але це рішення безпеки, а не зручності).
Якщо ціль старіша і не може коректно приймати зашифроване receive, або оновлюйте її, або прийміть реплікацію у відкритому вигляді і повторно зашифруйте на цілі.
Уявлення про третій варіант — як раз той шлях, що приводить до «тимчасових» незашифрованих бекапів не в тому місці.
Правило 4: інкрементальні потоки вимагають спільної історії
Інкрементальний send покладається на спільний снапшот (або bookmark), наявний з обох сторін. Якщо ціль втратила його, перейменувала або ніколи не отримувала,
інкрементальний send зазнає невдачі. Виправлення зазвичай — reseed повним send або використання правильно керованої ланцюжка bookmark.
Правило 5: рекурсія і властивості можуть бути небезпечними
zfs send -R зручний. Він також охоче реплікує властивості, яких ви можливо не хочете на цілі: mountpoint, sharenfs/smb,
квоти і дивні спадкові налаштування. Ставтеся до -R як до змін у продакшні, а не просто як до копіювання.
Практичні завдання: команди, виводи та рішення
Це перевірки, які я реально виконую перед і під час міграцій. Кожна містить, що означає вивід і яке рішення з нього випливає.
Запустіть їх на обох кінцях. Порівняйте. Не робіть припущень.
Завдання 1: Визначити реалізацію ZFS і версію (Linux)
cr0x@server:~$ modinfo zfs | egrep 'version:|srcversion:'
version: 2.2.2-1
srcversion: 1A2B3C4D5E6F7G8H9I0J
Значення: Це показує версію модуля OpenZFS на Linux. Це не вся картина, але орієнтир для очікувань.
Рішення: Якщо ціль значно старіша, плануйте консервативні потоки і очікуйте невідповідностей фіч.
Завдання 2: Визначити версію userland ZFS
cr0x@server:~$ zfs version
zfs-2.2.2-1
zfs-kmod-2.2.2-1
Значення: Модуль ядра і userland мають бути відносно узгодженими. Великі розбіжності можуть давати дивну поведінку.
Рішення: Якщо вони не узгоджені, виправте це перш ніж. Дебагувати реплікацію зі стеком наполовину оновленим — хобі, а не робота.
Завдання 3: Перевірити feature flags пулу на джерелі
cr0x@server:~$ zpool get -H -o name,property,value all tank | head
tank size 23.8T
tank capacity 61%
tank health ONLINE
tank ashift 12
tank autotrim off
Значення: Базова санність, і це підтверджує, що пул читається. Для сумісності цього ще недостатньо.
Рішення: Якщо health пулу не ONLINE, зупиніться і виправте це перед міграцією. Реплікація — не стратегія ремонту.
Завдання 4: Явно перелічити feature flags
cr0x@server:~$ zpool get -H -o property,value feature@* tank | egrep 'active|enabled' | head
feature@async_destroy active
feature@bookmarks active
feature@embedded_data active
feature@extensible_dataset active
feature@encryption active
feature@device_removal enabled
Значення: “active” означає використовується; “enabled” — доступна. Будь-що active на джерелі — червоний прапорець для старіших цілей.
Рішення: Порівняйте це з підтримкою пулу на цілі. Якщо ціль не підтримує active-фічу, потрібно або оновити ціль, або мігрувати іншим шляхом.
Завдання 5: Перевірити, які фічі підтримує пул цілі
cr0x@server:~$ zpool get -H -o property,value feature@* backup | head
feature@async_destroy enabled
feature@bookmarks enabled
feature@embedded_data enabled
feature@encryption disabled
feature@extensible_dataset enabled
feature@filesystem_limits enabled
Значення: Якщо потрібна фіча disabled через те, що реалізація її не знає, ви застрягли.
Якщо вона відключена, але відома, можливо, ви зможете увімкнути її.
Рішення: Якщо джерело вимагає feature@encryption active, а ціль показує feature@encryption disabled, або оновіть OpenZFS/пул цілі, або плануйте розшифровану міграцію (усвідомлено).
Завдання 6: Підтвердити стан шифрування датасету і роботу з ключами
cr0x@server:~$ zfs get -o name,property,value -H encryption,keylocation,keystatus tank/prod
tank/prod encryption aes-256-gcm
tank/prod keylocation file:///root/keys/prod.key
tank/prod keystatus available
Значення: Маємо справу з нативним шифруванням ZFS. Вибір реплікації важливий.
Рішення: Якщо потрібно зберегти шифрування, плануйте raw send і впевніться, що ціль це підтримує. Якщо прийнятне перешифрування, плануйте plaintext send і шифрування на цілі.
Завдання 7: Перелік снапшотів і перевірка наявності спільної бази
cr0x@server:~$ zfs list -t snapshot -o name,creation -s creation tank/prod | tail -3
tank/prod@replica_2025-12-20 Sat Dec 20 02:00 2025
tank/prod@replica_2025-12-21 Sun Dec 21 02:00 2025
tank/prod@replica_2025-12-22 Mon Dec 22 02:00 2025
Значення: Це показує ланцюжок снапшотів, доступний для інкрементальних відправок.
Рішення: Підтвердіть, що ціль також має базовий снапшот, який ви будете використовувати. Якщо ні — не можете робити інкрементал без reseed.
Завдання 8: Підтвердити, що ціль має базовий снапшот
cr0x@server:~$ zfs list -t snapshot -o name backup/prod | head -3
NAME
backup/prod@replica_2025-12-20
backup/prod@replica_2025-12-21
Значення: Добре: спільна історія існує.
Рішення: Продовжуйте з інкременталом із найновішого спільного снапшоту. Якщо його бракує — reseed або використайте стратегію з bookmark.
Завдання 9: Оцінити розмір send перед відправленням по WAN
cr0x@server:~$ zfs send -nP -i tank/prod@replica_2025-12-21 tank/prod@replica_2025-12-22
size 14839210496
incremental tank/prod@replica_2025-12-21 tank/prod@replica_2025-12-22
Значення: Близько 13.8 GiB логічних даних потоку (не обов’язково байти по дроту).
Рішення: Якщо це більше, ніж очікували, дослідіть churn (образи VM, бази даних, невідповідність recordsize) перед плануванням реплікації в пік.
Завдання 10: Dry-run receive для валідації прав і цільового датасету
cr0x@server:~$ zfs receive -nvu backup/prod
would receive incremental stream of tank/prod@replica_2025-12-22 into backup/prod
would destroy snapshots: none
would overwrite: none
Значення: -n — no-op, -v — verbose, -u — не монтувати. Це підверджує, що приймач розуміє потік і що він би зробив.
Рішення: Якщо це падає, не «просто запустіть все одно». Виправте іменування, права та невідповідності фіч.
Завдання 11: Виконати інкрементальний send з витривалістю
cr0x@server:~$ zfs send -v -i tank/prod@replica_2025-12-21 tank/prod@replica_2025-12-22 | ssh backup01 zfs receive -uF backup/prod
send from tank/prod@replica_2025-12-21 to tank/prod@replica_2025-12-22 estimated size is 13.8G
total estimated size is 13.8G
TIME SENT SNAPSHOT
02:00:12 13.8G tank/prod@replica_2025-12-22
Значення: -F може відкотити ціль, щоб відповідати; це корисно, але небезпечно.
Рішення: Використовуйте -F лише для виділених цілей реплікації, де відкат не знищить місцеві зміни. Якщо люди пишуть туди, приберіть -F і правильно вирішіть розбіжності.
Завдання 12: Проінспектувати помилку receive і зіставити її з сумісністю
cr0x@server:~$ zfs receive -u backup/prod
cannot receive incremental stream: most recent snapshot of backup/prod does not match incremental source
Значення: Базовий снапшот на цілі відрізняється від того, який ви відправляєте (або був відкотений/перейменований).
Рішення: Знайдіть найновіший спільний снапшот або reseed повним send. Не змушуйте це відкатом, якщо ціль не є тимчасовою.
Завдання 13: Перевірити holds, щоб запобігти видаленню снапшоту під час потоку
cr0x@server:~$ zfs holds tank/prod@replica_2025-12-22
NAME TAG TIMESTAMP
tank/prod@replica_2025-12-22 repl Fri Dec 22 02:00 2025
Значення: Hold запобігає автоматичному видаленню снапшоту, який вам ще потрібен.
Рішення: Якщо ви запускаєте pruning снапшотів, використовуйте holds (або bookmarks), щоб інкрементальні ланцюжки не були «вичищені» і не провалилися.
Завдання 14: Використовувати bookmarks для довготривалих інкрементальних якорів
cr0x@server:~$ zfs bookmark tank/prod@replica_2025-12-22 tank/prod#bkm_2025-12-22
cr0x@server:~$ zfs list -t bookmark -o name,creation tank/prod | tail -1
tank/prod#bkm_2025-12-22 Mon Dec 22 02:00 2025
Значення: Bookmarks — легкі посилання, що дозволяють робити інкрементальне відправлення без зберігання повного снапшоту вічно.
Рішення: Якщо тиск на збереження високий, переходьте на bookmarks. Але тестуйте підтримку приймача; старі системи можуть не обробляти інкрементали з bookmark.
Завдання 15: Підтвердити поведінку mountpoint і canmount перед використанням -R
cr0x@server:~$ zfs get -o name,property,value -H mountpoint,canmount tank/prod
tank/prod mountpoint /prod
tank/prod canmount on
Значення: Якщо ви реплікуєте властивості, можете випадково змонтувати продакшн-шляхи на бекап-сервері. Це не «упс» — це аварія.
Рішення: На цілі використовуйте zfs receive -u і встановлюйте безпечні mountpoint. Розгляньте можливість очищення або перевизначення властивостей.
Завдання 16: Підтвердити, що цільовий датасет не змонтований (або змонтувати безпечно)
cr0x@server:~$ zfs get -o name,property,value -H mounted,mountpoint backup/prod
backup/prod mounted no
backup/prod mountpoint /backup/prod
Значення: Добре: він не примарно замонтується поверх чогось.
Рішення: Тримайте цілі реплікації зазвичай розмонтованими; монтуйте лише коли треба читати або відновлювати.
Вибір правильних опцій zfs send (і коли не варто)
Почніть консервативно, потім додавайте можливості
При відправленні на старішого приймача ваша мета — нудна сумісність, а не кмітливість. Найбільш сумісний підхід зазвичай такий:
початковий full send для seed, потім інкрементали з мінімумом «крутого» функціоналу.
Raw vs non-raw при шифруванні
Якщо датасет зашифрований і ви хочете зберегти його «як є» (той самий ciphertext, ключі не розкриваються), потрібен raw send. Залежно від платформи,
це зазвичай zfs send -w (raw) і receive на цілі, що підтримує зашифрований receive.
cr0x@server:~$ zfs send -w tank/prod@replica_2025-12-22 | ssh backup01 zfs receive -u backup/prod
cannot receive: stream is encrypted but encryption feature is disabled
Значення: Ціль не може прийняти зашифрований/raw потік, бо її пул або реалізація не має підтримки шифрування.
Рішення: Оновіть OpenZFS та feature flags пулу цілі, або перейдіть на non-raw send (приймаючи передачу plaintext) і повторно зашифруйте на цілі.
Стиснений send: добре, доки не перестає бути
Стиснений send може зменшити пропускну здатність і CPU у деяких випадках, але залежить від підтримки приймача. На змішаних версіях розглядайте це як оптимізацію,
яку ви заробили, а не як налаштування за замовчуванням.
Потоки реплікації (-R) і мінні поля властивостей
-R потрібен для реплікації піддерева зі снапшотами, властивостями і дочірніми датасетами. Ідеально під DR-цілі.
Але це також зручний спосіб реплікувати небезпечні mountpoint у невірне місце.
cr0x@server:~$ zfs send -R tank/prod@replica_2025-12-22 | ssh backup01 zfs receive -u backup/tank
receiving full stream of tank/prod@replica_2025-12-22 into backup/tank/prod
Значення: Ви відтворюєте структуру на цілі. Властивості можуть прилетіти разом.
Рішення: Якщо ціль не є дзеркалом оточення, уникати -R. Або використовуйте його, але негайно перевизначайте небезпечні властивості на цілі.
Force receive (-F): іноді потрібен, часто зловживають
zfs receive -F відкочується на цілі, щоб відповідати потоку. Він виправляє розбіжності. Але також видаляє снапшоти і місцеві зміни, що конфліктують.
У корпоративних термінах -F — це скорочення штату: ефективно, швидко, і вам краще мати санкції.
Сумісність датасету: recordsize, volblocksize і великі блоки
Самі властивості датасету можуть спричинити несподівану продуктивність, навіть якщо потік прийнято. Новіше джерело з великим recordsize і тонко налаштованими
параметрами може реплікуватися на старішу ціль, яка технічно приймає все, але потім відновлення працює дивно і ваші припущення ламаються.
Жарт №2: Якщо хочете пригод — реплікуйте бази даних через ненадійний VPN; якщо хочете спокійного сну — зробіть full send на вихідних вихідних і візьміть снеки.
Три корпоративні історії з фронту реплікації
Інцидент: хибне припущення про «версійну сумісність»
Середня компанія мігрувала зі старого FreeBSD-сховища на Linux-аплайанс з новішим OpenZFS. План виглядав простим:
seed нового боксу, переключити NFS-експорти, вивести старе обладнання з експлуатації. Хтось спитав: «Чи сумісні версії ZFS?» і почув впевнене «Так, ZFS — то ZFS.»
Це обійшлося їм у вихідні.
Пул-джерело мав кілька активних feature flags (bookmarks, embedded_data, large_blocks). OpenZFS цілі підтримував деякі з них, але пул на аплайансі ніколи не оновлювався
і мав консервативний набір фіч, бо поставлявся так. Під час початкових тестів вони реплікували невеликий датасет без активації нових фіч. У продакшні ж основний датасет вимагав їх.
Receive впав на півшляху через seed-потік. Повідомлення про помилку не допомагало; воно виглядало як загальна помилка receive. Вони повторили спробу, отримали інші помилки,
і потрапили в класичну пастку: «Може, проблема в мережі». Ні — проблема була в контракті пулу.
Виправлення було нудним: явно оновити цільовий пул для підтримки потрібних feature flags, потім перезасіювати. Але reseed означав ще один довгий трансфер,
і вікно cutover вже було заброньоване. Вони врешті зробили часткову міграцію і тягли старе залізо тижнями.
Урок не в тому, щоб «оновити все». Урок — інвентаризуйте фічі перед тим, як рухати байти, і ставте оновлення пулу в процеси зміни з планом відкату (який зазвичай означає «реплікуйте кудись ще», а не «скасуйте»).
Оптимізація, що відплатилася: агресивні прапорці в змішаному парку
Інший офіс мав мережу віддалених точок, кожна з маленьким ZFS-боксом, що реплікувався в центральний DR-кластер. Полоса була обмеженою й дорогою. Інженер
вирішив «зменшити потік», включивши стиснений send і рекурсію всюди, та використовуючи force receive, щоб тримати все вирівняним.
Спочатку це працювало, що найнебезпечніше для зміни. З часом кілька офісів оновили ZFS під час оновлень ОС, інші лишилися за старими обмеженнями. Скрипт реплікації
не звертав уваги; він використовував однакові прапорці для всіх.
Деякі приймачі почали періодично падати на одному класі датасетів — VM zvols. Збої співпали зі зміною того, як ті системи створювали снапшоти і що потоки містили.
Скрипт з zfs receive -F почав відкотувати і повторно застосовувати стан постійно. Дані не були корумповані, але цілі відновлення тихенько погіршилися,
бо конвеєр витрачав час на боротьбу з самим собою.
Вони зрештою виявили дві речі: по-перше, стиснений send не був однаково підтриманий у різних версіях приймача для специфічних форм потоку;
по-друге, -F маскував базову проблему «відсутній спільний снапшот», постійно переписуючи історію приймача, що робило інкрементальні ланцюжки крихкими.
Виправлення — розбити парк на рівні сумісності. Консервативні потоки для старих приймачів, сучасні потоки для нових, і прибрати -F, крім виділених цілей-дзеркал.
Пропускна здатність трохи зросла. Сон покращився значно.
Нудна, але правильна практика, яка врятувала день: інвентар фіч + покрокове seed
Команда фінпослуг планувала переїзд датацентру. ZFS був з обох боків, але ціль управлялася іншим відділом з іншим циклом оновлень.
Замість поспіху з прапорцями вони дотрималися простої дисципліни: інвентар фіч пулу і властивостей датасету, потім узгодження базової сумісності.
Вони створили staging-пул на цілі, достатній для повних seed, і робили dry-run receive в робочий час, щоб підтвердити, що потоки будуть парситись і не міститимуть руйнівних дій.
Використовували zfs send -nP для оцінок розміру і snapshot holds, щоб автоматичне очищення не зламало інкременти в вікні cutover.
Під час реального переміщення мережа погано працювала. Трансфери сповільнилися і зупинилися. Але оскільки більшість датасетів вже була засеяна і інкрементальна сумісність перевірена,
їм залишилися лише малі дельти для cutover. Повільна мережа стала незручністю, а не кризою.
Нічого героїчного не сталося. Ось у чому суть. Правильна практика виглядала нудною на статусних зустрічах, але зменшила кількість невідомих майже до нуля.
Швидкий план діагностики
Коли реплікація ламається або повільна, потрібен короткий цикл: визначити, чи це невдача сумісності, невідповідність історії або вузьке місце пропускної здатності.
Перевіряйте по порядку. Не стрибайте одразу до налаштувань.
По-перше: це помилка сумісності?
- На цілі спробуйте dry-run receive:
zfs receive -nvu target/ds. Якщо парсинг падає, це сумісність потоку або права. - Порівняйте feature flags:
zpool get feature@* srcpoolvszpool get feature@* dstpool. - Перевірте стан шифрування:
zfs get encryption,keystatus. Якщо ви використовуєте raw send, ціль має підтримувати шифрування.
По-друге: це невідповідність інкрементальної історії?
- Підтвердьте, що обидві сторони мають базовий снапшот:
zfs list -t snapshot | grep. - Перевірте розбіжність на цілі: чи хтось робив локальні снапшоти, відкот або видаляв снапшоти?
- Якщо ви використовуєте bookmarks, перевірте, що вони існують на обох кінцях (або що ваш send використовує snapshot-to-snapshot, а не bookmark-to-snapshot).
По-третє: це вузьке місце пропускної здатності?
- Оцініть розмір потоку:
zfs send -nP. Якщо він величезний — «вузьке місце» може бути churn, а не мережа. - Перевірте CPU і стиснення: якщо ви стискаєте на льоту зовні, CPU може бути лімітом.
- Спостерігайте мережу і SSH: якщо через SSH, вибір шифру і однопоточність можуть обмежувати пропускну здатність.
- Перевірте продуктивність пулу: цільовий пул може бути фрагментований, зайнятий або мати sync-настройки, що обмежують запис.
Цей план навмисно не гламурний. У продакшні найшвидше виправлення зазвичай — “коректне припущення”, а не “хитра оптимізація”.
Поширені помилки: симптом → корінь → виправлення
1) «cannot receive: unsupported feature or stream»
Симптом: Receive падає одразу; помилка згадує unsupported feature/stream або просто «invalid stream».
Корінь: Приймач на цілі не розуміє типів записів потоку, або пул цілі не може підтримати потрібні фічі.
Виправлення: Порівняйте zpool get feature@* і відрегулюйте. Оновіть OpenZFS/пул цілі або відправте більш консервативний потік (уникайте raw/compressed/replication прапорців, поки не перевірите).
2) «most recent snapshot does not match incremental source»
Симптом: Інкрементальний send падає; на цілі є снапшоти, але не той, який ви очікували.
Корінь: Втрачені спільні базові снапшоти через pruning, перейменування, ручне знищення або відкат цілі.
Виправлення: Знайдіть найновіший спільний снапшот і відправляйте інкременти від нього. Якщо жодного немає — reseed повним send. Додайте holds або bookmarks, щоб уникнути повторення.
3) Реплікація «пройшла», але ціль змонтувалася поверх критичного ресурсу
Симптом: Раптово дивний вміст файлової системи на цілі; сервіси читають неправильні дані; змінені mountpoints.
Корінь: Репліковані властивості (часто через -R) застосували mountpoint/canmount/shares.
Виправлення: Завжди приймайте з -u у безпечні шляхи; встановлюйте mountpoint/canmount після receive. Уникайте реплікації властивостей, якщо ціль не справжнє дзеркало.
4) Raw зашифрований send падає на цілі
Симптом: Помилки про encryption feature disabled або проблеми з ключами.
Корінь: OpenZFS/пул цілі не підтримує шифрування або ключі некоректно обробляються для режиму receive.
Виправлення: Оновіть ціль для підтримки шифрування і увімкніть потрібні feature flags пулу, або зробіть розшифровану міграцію і повторно зашифруйте на цілі з новими ключами.
5) «zfs receive» повільний і завантажує CPU
Симптом: Мережа не завантажена; CPU гарячий; реплікація повзе.
Корінь: Ви робите важке стиснення/шифрування в userland (SSH-шифр, зовнішнє стиснення), або цільовий пул є вузьким місцем.
Виправлення: Зменшіть навантаження userland (виберіть адекватні SSH-шифри, уникайте непотрібного стиснення), перевірте IOPS цільового пулу і уникайте накладання стиснення на вже стиснені дані.
6) Інкременти випадково ламаються після «очистних задач»
Симптом: Працює дні, а потім падає після виконання pruning снапшотів.
Корінь: Політика утримання видаляє базовий снапшот, потрібний для інкрементів.
Виправлення: Використовуйте snapshot holds для якорів реплікації або переходьте на bookmarks; узгодьте утримання з частотою реплікації і лагом.
7) Використання простору на цілі вибухоподібно зростає після міграції
Симптом: Та сама логічна кількість даних, але більше спожитого простору на цілі.
Корінь: Різні налаштування стиснення, різниця recordsize, особлива поведінка vdev або ціль не отримує стислих блоків як очікувалося.
Виправлення: Перевірте zfs get compression,recordsize і відмінності в плануванні пулу. Не припускайте ідентичного фізичного використання між пулами; перевіряйте на малих зразках.
Контрольні списки / покроковий план
План A: Безпечна міграція з нового джерела на старішу ціль
-
Інвентар фіч і шифрування.
Запустіть на джерелі і цілі:zpool get feature@*,zfs get encryption,keystatus.
Вирішіть: оновлювати ціль чи приймати розшифровану міграцію. -
Створіть виділений цільовий датасет.
Тримайте його розмонтованим: receive з-u. Вирішіть: потрібне дзеркало (-R) чи одиночний датасет? -
Dry-run receive.
Використовуйтеzfs receive -nvu, щоб впіймати проблеми парсингу/прав без запису. -
Seed повним send.
Першопочатково уникайте хитрих прапорців. Перевірте, що снапшот на цілі існує після receive. -
Перейдіть на інкрементальні відправки.
Використовуйте послідовне іменування снапшотів; захищайте якорі holds або bookmarks. -
Cutover.
Останній інкремент, перевірте цілісність на рівні застосунків, потім переключайте клієнтів.
План B: Створення стандарту реплікації в змішаних версіях ZFS
- Визначте рівні сумісності. Групуйте системи за можливостями приймача; не використовуйте єдиний «універсальний» набір прапорців.
- Виберіть за замовчуванням консервативний потік. Додавайте raw/compressed/recursion тільки після валідації для кожного рівня.
- Стандартизуйтесь у іменуванні снапшотів і bookmark. Ваш майбутній ви потребуватиме детерміністичного узгодження, а не креативності.
- Автоматизуйте валідацію. Періодично перевіряйте наявність спільних снапшотів і що dry-run receives успішні.
- Документуйте політику оновлення пулів. Оновлення пулу незворотні; ставте їх у процес змін з погодженням.
План C: Коли інкременти зламались і треба повернути сервіс
- Припиніть видаляти снапшоти. Призупиніть retention jobs.
- Знайдіть найновіший спільний снапшот. Якщо він є, відновіть інкременти з нього.
- Якщо спільного снапшоту немає — reseed. Повний send останнього снапшоту; потім відновіть інкрементальний ланцюжок.
- Після відновлення реалізуйте holds/bookmarks. Запобіжте повторним відмовам через очистку.
Додаткові операційні запобіжники (зробіть це — подякуєте собі пізніше)
- Цілі реплікації ставте як «cattle»: виділені, неінтерактивні і здатні до відкату.
- Ніколи не реплікуйте mountpoints у хост, де також працюють застосунки, якщо ви не контролюєте властивості явно.
- Протестуйте один датасет end-to-end, включно з відновленням, перш ніж планувати «велику міграцію».
FAQ
1) Чи може новіший OpenZFS завжди відправити в старіший OpenZFS?
Ні. Приймач має розуміти формат потоку, і пул цілі повинен підтримувати потрібні фічі. «ZFS — то ZFS» — це не контракт.
2) Який найбільший індикатор несумісності?
Активні feature flags пулу на джерелі, які ціль не підтримує. Перевірте zpool get feature@* і шукайте «active» на джерелі і «disabled/unsupported» на цілі.
3) Якщо пул цілі підтримує фічу, але вона не enabled, чи receive її увімкне?
Може, залежно від реалізації і структур, що записуються. На практиці варто явно керувати оновленнями пулу, щоб не активувати незворотні фічі випадково під час міграції.
4) Чи потрібен raw send для зашифрованих датасетів?
Потрібен, якщо ви хочете зберегти шифрування як ciphertext end-to-end. Якщо не використовуєте raw, може відправлятися plaintext (навіть якщо джерело було зашифроване) — це рішення безпеки.
5) Чому інкрементальний send жаліється на несумісність снапшотів, коли імена схожі?
Імена — не ідентичність. Снапшот на цілі може бути іншим станом (наприклад, з іншої історії), або ціль була відкотана. Інкрементали вимагають спільного предка в історії.
6) Чи завжди варто використовувати zfs send -R для реплікації?
Лише якщо ціль має стати вірною копією піддерева, включаючи властивості і дочірні датасети. Інакше -R може реплікувати «умови середовища», які ви не хотіли копіювати.
7) Коли доцільно використовувати zfs receive -F?
Для виділених реплікаційних цілей, де відкат прийнятний і очікуваний. Не для спільних датасетів, не для місць, куди пишуть люди, і не як пластир для зламаного утримання снапшотів.
8) Як bookmarks допомагають зі сумісністю та утриманням?
Bookmarks дозволяють інкрементальні відправки без зберігання кожного старого снапшоту. Вони знижують тиск на збереження і запобігають зламам інкрементів автоматичними очистками — якщо обидва кінці підтримують bookmark-based sends.
9) Чому оцінка розміру send не збігається з реально переданими байтами?
Оцінка — це логічний розмір потоку. Байти по дроту залежать від того, чи блоки вже стиснені, чи сам потік стиснений, і який мережевий/SSH-овий оверхед додається.
10) Чи можу я «понизити» пул, щоб відповідати старшій системі і щоб реплікація працювала?
Реально — ні, не на місці. Коли фічі активовані, зазвичай назад не повернутись. Практичне пониження — створити сумісний пул і реплікувати в нього, використовуючи сумісні потоки.
Висновок: практичні наступні кроки
Якщо взяти одну операційну позицію з цього: сумісність — це не відчуття, це інвентар. Не «пробуйте send і сподівайтеся». Перевірте feature flags пулу,
стан шифрування датасету, можливості приймача і історію снапшотів спочатку — а потім рухайте байти.
Наступні кроки, які можна зробити сьогодні:
- Запустіть
zpool get feature@*на кожному кінці реплікації і збережіть виводи у зручному місці для порівняння. - Виберіть консервативний режим реплікації для старіших приймачів і застосовуйте його по рівнях сумісності.
- Реалізуйте holds або bookmarks, щоб утримання не ламало інкрементальний ланцюжок.
- Практикуйте відновлення, а не лише відправлення. Реплікація, яку не можна коректно отримати і змонтувати, — це просто дорогий стрімінг.