Панель моніторингу резервних копій зелена. Ваші снапшоти «працюють». Аудитори заспокоєні.
Потім трапляється реальний інцидент — викуплення, випадкове rm -rf, вихід з ладу контролера або хтось «допоміжно» видаляє датасет — і раптом ви публічно вчитесь, що насправді означає «відновити».
Тренування DR із ZFS send/receive — це момент, коли ви міняєте заспокійливу теорію на виміряну реальність: скільки це займає часу, що ламається, чого не вистачає і що хотілося б протестувати ще минулого кварталу.
Резервні копії — це процес. Відновлення — це продуктивність.
Чому тренування DR з ZFS важливе (і що воно насправді перевіряє)
Реплікація ZFS send/receive спокуслива, бо виглядає детерміністично: снапшот A відправили — снапшот A отримано, і навіть можна виміряти байти в дорозі.
Це заохочує небезпечну звичку: вважати реплікацію тотожною відновленню.
Тренування DR — це не «чи можемо ми скопіювати дані». Це «чи можемо ми відновити сервіс», з усіма неприємними деталями:
- Ідентичність: чи правильні імена датасетів, mountpoint-и та права доступу на цільовій стороні?
- Залежності: чи потрібні ще WAL PostgreSQL, конфігурації додатка, секрети, TLS-ключі або метадані VM?
- Час: чи вкладаєтесь ви в RPO і RTO, коли мережа завантажена, а черговий втомлений?
- Безпека: чи можна зробити це без затирання останньої доброї копії?
- Люди: чи хтось крім «ZFS-фахівця» знає, що вводити?
Ви не проводите DR-тренування, щоб довести, що ZFS працює. ZFS працює. Ви проводите тренування, щоб впіймати те, що не працює: ваші припущення, автоматизацію, керування ключами,
правила іменування та звичку не документувати ту дивну дію, яку ви робили три роки тому о 2:00 ночі.
Одна операційна цитата, що добре збереглася: Надія — це не стратегія.
— James Cameron.
Вона з соромною точністю підходить до відновлення резервних копій.
Жарт #1: Резервні копії — як парашути: якщо ви їх не тестували, ви дуже швидко дізнаєтеся багато нового.
Цікавинки та коротка історія
Трохи контексту корисно, бо ZFS send/receive — це не «проста копія файлів». Це потік стану файлової системи, і рішення дизайну за ним пояснюють
багато різких кутів, з якими ви зіткнетеся під час тренувань.
- Реплікація снапшотів старша за хмарну модність: send/receive існує з ранніх днів ZFS, створений для реальних корпоративних робочих процесів реплікації.
- Потоки ZFS транзакційні: ви відправляєте блоки і метадані файлової системи станом на снапшот, а не «застосовуєте зміни файлів», як rsync.
- Інкрементали залежать від походження: інкрементальний потік вимагає наявності на отримувачі точної базової миттєвої копії (такий же GUID lineage), а не просто снапшота з тим же ім’ям.
- Властивості можуть передаватися: з
-pі суміжними прапорами властивості датасетів можуть реплікуватися, що залежно від конвенцій цілі може бути спасінням або хаосом. - Шифрування змінило правила гри: вбудоване шифрування ZFS внесло керування ключами у реплікацію — особливо «raw» send і завантаження ключів на приймачі.
- Стиснення — не «безкоштовна пропускна здатність»: розмір потоку ZFS дуже варіюється залежно від recordsize, compressratio і того, чи відправляєте ви стиснені чи raw дані.
- Receive не завжди ідемпотентний: повторні receive можуть падати або відрізнятися, якщо снапшоти були обрізані, зроблено rollback або попередній receive залишив частковий стан.
- Реплікація — не збереження ретеншену: send/receive дзеркалить історію снапшотів, яку ви обрали; це не вирішує автоматично ретеншен, legal hold або офлайн-копії.
- ZFS завжди про цілісність: контрольні суми дійсні наскрізно, але тренування виявляють реальні проблеми: погані кабелі, нестабільна RAM, неправильно налаштований arc або перевантажений пул приймача.
Визначте тренування: масштаб, RPO/RTO і критерій «завершено»
Не починайте з команд. Почніть з визначень, бо DR-тренування найчастіше провалюються як проєктні невдачі в технічній масці.
Визначте три речі перед тим, як торкнутися shell:
1) Що ви відновлюєте?
Виберіть один сервіс із достатньою складністю, щоб бути чесним: вебдодаток з базою даних, файловий шар з ACL, VM-робоче навантаження або аналітичний конвеєр.
Включіть «все, що потрібно для роботи» цього сервісу, а не лише його головний датасет.
2) Який RPO і RTO ви будете вимірювати?
- RPO: найновіший прийнятний снапшот, який можна відновити (наприклад, «не більше ніж 15 хвилин втрати даних»).
- RTO: час від оголошення аварії до відновлення доступності для користувачів (наприклад, «менше 2 годин»).
Для реплікації ZFS ви часто можете контролювати RPO частотою створення снапшотів та інтервалом реплікації. RTO — це місце, де реальність кусає:
пропускна здатність мережі, продуктивність пулу приймача, завантаження ключів, порядок монтування, перевірки сервісів, DNS та відновлення на рівні додатка.
3) Як виглядає «завершено»?
«Датасет отримано успішно» — це не «завершено». «Додаток проходить smoke-тести» ближче до істини.
Ваше визначення завершення має включати:
- Датасети змонтовані так, як очікується (або навмисно не змонтовані до переключення).
- Сервіси запущені й здорові.
- Права й власність правильні.
- Хоча б один реальний шлях читання/запису перевірено (вхід в систему працює, запит працює, створення файлу працює).
- Заміри тривалості для кожної фази (тривалість receive, час монтування, час відновлення додатка).
Підготовка: що побудувати перед практикою
Тренування DR має відчуватися як репетиція. Не тому, що це театр, а тому, що коли воно реальне — у вас не буде часу вигадувати хореографію.
Побудуйте це заздалегідь.
Імена, які не зашкодять пізніше
Визначте, як сторона DR іменує пули й датасети. Якщо ви реплікуєте tank/prod/app у backup/prod/app, це — вибір щодо
mountpoint-ів, очікувань fstab і інструментів.
Я рекомендую отримувати в окремий пул і простір імен на хості DR, наприклад drpool/recv/prod/app, а потім контролювати промоцію/перейменування при переключенні.
Це уникне випадкового монтування поверх продуктивних шляхів під час тренування.
Керування ключами (якщо ви використовуєте нативне шифрування)
Якщо ваші датасети зашифровані, реплікація — це не просто «дані». Це ключі, місця зберігання ключів і хто може їх завантажити під тиском.
Визначте, чи хост DR зберігає ключі (ризиковано, але швидше) або вимагає ручного завантаження ключів (безпечніше, але повільніше).
У будь-якому разі — відпрацюйте це.
Автоматизація, яка навмисно нудна
Автоматизація DR має бути передбачувано нудною: явні імена снапшотів, явні цілі receive, логування у файл і негайне завершення при невідповідності.
Не вигадуйте хитрощів із «останнім снапшотом» без запобіжників.
Реальність ємності та фрагментації
Реплікація не врятує вас від недостатньої ємності на DR. ZFS не вражається оптимізмом.
Розмірьте пул DR так, щоб помістити: репліковані датасети, ретеншен снапшотів і місце для прийому стріму (потрібний запас).
Якщо ви близькі до заповнення, ваше тренування має включати момент, коли receive зупиняється в середині потоку.
Практичні завдання (команди, виводи, рішення)
Ці завдання призначені для виконання під час тренування DR (або підготовки до нього). Кожне включає:
команду, реалістичний вивід, що це означає, і рішення, яке з цього випливає.
Імена хостів і пулів — приклади: prod1 відправляє з tank, dr1 приймає в drpool.
Завдання 1: Підтвердити стан пулу перед реплікацією
cr0x@prod1:~$ zpool status -x
all pools are healthy
Що це означає: Немає відомих помилок vdev. Це ваша базова лінія.
Рішення: Якщо це не так, зупиніться. Не реплікуйте корупцію та не називайте це DR.
Завдання 2: Перевірити вільне місце і фрагментацію (відправник і приймач)
cr0x@prod1:~$ zpool list -o name,size,alloc,free,frag,cap,health
NAME SIZE ALLOC FREE FRAG CAP HEALTH
tank 7.25T 5.10T 2.15T 28% 70% ONLINE
cr0x@dr1:~$ zpool list -o name,size,alloc,free,frag,cap,health
NAME SIZE ALLOC FREE FRAG CAP HEALTH
drpool 9.06T 3.40T 5.66T 12% 37% ONLINE
Що це означає: Приймач має достатньо вільного місця; фрагментація помірна.
Рішення: Якщо CAP > 80% або frag високий, очікуйте повільніші receives і можливий ENOSPC при збереженні снапшотів. Виправте ємність перед тренуванням.
Завдання 3: Перевірити список датасетів і критичні властивості
cr0x@prod1:~$ zfs list -r -o name,used,avail,recordsize,compression,encryption,mountpoint tank/prod/app
NAME USED AVAIL RECORDSIZE COMPRESS ENCRYPTION MOUNTPOINT
tank/prod/app 820G 1.20T 128K zstd aes-256-gcm /srv/app
tank/prod/app/db 540G 1.20T 16K zstd aes-256-gcm /var/lib/postgresql
tank/prod/app/logs 120G 1.20T 128K zstd aes-256-gcm /srv/app/logs
Що це означає: Recordsize відрізняється між додатком і БД, стиснення zstd, шифрування ввімкнено.
Рішення: Переконайтеся, що ціль DR сумісна з цими властивостями. Для тренувань уникайте сліпого успадкування mountpoint-ів, які можуть конфліктувати з локальними шляхами.
Завдання 4: Підтвердити частоту снапшотів і «останню безпечну точку» (RPO)
cr0x@prod1:~$ zfs list -t snapshot -o name,creation -s creation -r tank/prod/app | tail -n 5
tank/prod/app@dr-2025-12-26_1000 Fri Dec 26 10:00 2025
tank/prod/app@dr-2025-12-26_1015 Fri Dec 26 10:15 2025
tank/prod/app@dr-2025-12-26_1030 Fri Dec 26 10:30 2025
tank/prod/app@dr-2025-12-26_1045 Fri Dec 26 10:45 2025
tank/prod/app@dr-2025-12-26_1100 Fri Dec 26 11:00 2025
Що це означає: Снапшоти кожні 15 хвилин. Ваш RPO обмежується цим графіком плюс відставання реплікації.
Рішення: Якщо снапшоти не регулярні, реплікація не зможе досягти RPO, який ви не спроєктували.
Завдання 5: Виміряти затримку реплікації, порівнявши останні снапшоти відправника і приймача
cr0x@dr1:~$ zfs list -t snapshot -o name,creation -s creation -r drpool/recv/prod/app | tail -n 3
drpool/recv/prod/app@dr-2025-12-26_1030 Fri Dec 26 10:30 2025
drpool/recv/prod/app@dr-2025-12-26_1045 Fri Dec 26 10:45 2025
drpool/recv/prod/app@dr-2025-12-26_1100 Fri Dec 26 11:00 2025
Що це означає: Приймач має останній снапшот. Зараз затримка практично нульова.
Рішення: Якщо приймач відстає, вирішіть, чи використовувати в тренуванні найновіший отриманий снапшот (реалістично) або призупинити продакшн для синхронізації (менш реалістично).
Завдання 6: Приблизна оцінка розміру інкрементального відправлення
cr0x@prod1:~$ zfs send -nPv -I tank/prod/app@dr-2025-12-26_1045 tank/prod/app@dr-2025-12-26_1100
send from @dr-2025-12-26_1045 to tank/prod/app@dr-2025-12-26_1100 estimated size is 14.2G
total estimated size is 14.2G
Що це означає: Приблизно 14.2G змінилося між снапшотами. Це ваше навантаження реплікації за інтервал.
Рішення: Порівняйте з доступною пропускною здатністю і вікном реплікації. Якщо не встигаєте доставити дельту вчасно — не відповідатимете RPO під навантаженням.
Завдання 7: Виконати початкову повну реплікацію в безпечний простір імен
cr0x@prod1:~$ zfs send -w tank/prod/app@dr-2025-12-26_1100 | ssh dr1 "zfs receive -u -o mountpoint=none -d drpool/recv"
receiving full stream of tank/prod/app@dr-2025-12-26_1100 into drpool/recv/tank/prod/app@dr-2025-12-26_1100
Що це означає: -w відправляє raw зашифрований потік (ключі лишаються на відправнику; властивості шифрування зберігаються). -u запобігає авто-монтуванню при receive. -o mountpoint=none уникає випадкового монтування в критичні шляхи.
Рішення: Якщо ви хочете, щоб DR-хост монтував і обслуговував дані, потрібно спланувати завантаження ключів і коригування mountpoint-ів. Якщо це лише репліка, краще тримати її незмонтованою за замовчуванням.
Завдання 8: Інкрементальна реплікація (щоденна робота)
cr0x@prod1:~$ zfs send -w -I tank/prod/app@dr-2025-12-26_1100 tank/prod/app@dr-2025-12-26_1115 | ssh dr1 "zfs receive -u -dF drpool/recv"
receiving incremental stream of tank/prod/app@dr-2025-12-26_1115 into drpool/recv/tank/prod/app@dr-2025-12-26_1115
Що це означає: -I відправляє всі проміжні снапшоти. -F примусово відкочується приймач до найновішого снапшоту, щоб прийняти потік.
Рішення: Використовуйте -F лише коли впевнені, що датасет на приймачі — чиста репліка і ви погоджуєтеся втратити локальні зміни. У тренуваннях задокументуйте, коли його використовували.
Завдання 9: Підтвердити стан на стороні приймача і що датасети не змонтовані
cr0x@dr1:~$ zfs get -r -o name,property,value mounted,mountpoint drpool/recv/tank/prod/app | head
NAME PROPERTY VALUE SOURCE
drpool/recv/tank/prod/app mounted no -
drpool/recv/tank/prod/app mountpoint none local
drpool/recv/tank/prod/app/db mounted no -
drpool/recv/tank/prod/app/db mountpoint /var/lib/postgresql received
Що це означає: Верхній датасет незмонтований з mountpoint none, але дитячий має отриманий mountpoint. Класична ситуація «сюрпризного» майбутнього монтування.
Рішення: Нормалізуйте mountpoint-и на стороні отримання. Для простору реплік я віддаю перевагу встановленню mountpoint=none на всьому дереві, а потім явній установці mountpoint-ів лише на відновленому клоні.
Завдання 10: Безпечно перевизначити успадковані/отримані mountpoint-и
cr0x@dr1:~$ zfs set -r mountpoint=none drpool/recv/tank/prod/app
cr0x@dr1:~$ zfs get -r -o name,property,value mountpoint drpool/recv/tank/prod/app | head -n 6
NAME PROPERTY VALUE SOURCE
drpool/recv/tank/prod/app mountpoint none local
drpool/recv/tank/prod/app/db mountpoint none local
drpool/recv/tank/prod/app/logs mountpoint none local
Що це означає: Ви нейтралізували mountpoint-и по всьому дереву репліки.
Рішення: Тримайте репліки інертними. Створюйте окремий «відновлений екземпляр» (клон або promote) з реальними mountpoint-ами для запуску сервісів.
Завдання 11: Створити записувану відновлену копію, не торкаючись репліки
cr0x@dr1:~$ zfs clone drpool/recv/tank/prod/app@dr-2025-12-26_1115 drpool/restore/prod/app
cr0x@dr1:~$ zfs set mountpoint=/srv/app drpool/restore/prod/app
cr0x@dr1:~$ zfs mount drpool/restore/prod/app
cr0x@dr1:~$ zfs list -o name,mountpoint,origin drpool/restore/prod/app
NAME MOUNTPOINT ORIGIN
drpool/restore/prod/app /srv/app drpool/recv/tank/prod/app@dr-2025-12-26_1115
Що це означає: Тепер у вас є записуваний клон для тренування, залишаючи репліку недоторканою.
Рішення: Завжди відновлюйте у новий датасет, коли це можливо. Це запобіжник від людської помилки і дозволяє повторювати тренування.
Завдання 12: Завантажити ключі шифрування на стороні DR (за потреби)
cr0x@dr1:~$ zfs get -o name,property,value keystatus,encryptionroot drpool/restore/prod/app
NAME PROPERTY VALUE
drpool/restore/prod/app keystatus unavailable
drpool/restore/prod/app encryptionroot drpool/recv/tank/prod/app
cr0x@dr1:~$ zfs load-key -L file:///etc/zfs/keys/prod_app.key drpool/restore/prod/app
cr0x@dr1:~$ zfs get -o name,property,value keystatus drpool/restore/prod/app
NAME PROPERTY VALUE
drpool/restore/prod/app keystatus available
Що це означає: Ключі були недоступні, поки ви їх не завантажили. Без цього монтування і запуск сервісів не вдасться.
Рішення: У вашому раннбуку зробіть завантаження ключів явним, зазначте, хто має доступ і де ключі зберігаються. Якщо відповідь — «у чиїйсь домашній директорії», виправте це до наступного тренування.
Завдання 13: Виміряти реальну пропускну здатність конвеєра send/receive
cr0x@prod1:~$ zfs send -w tank/prod/app@dr-2025-12-26_1115 | pv -brt | ssh dr1 "zfs receive -u -d drpool/recv"
2.10GiB 0:00:18 [ 119MiB/s] [ <=> ]
Що це означає: Кінцева пропускна здатність приблизно 119MiB/s. Це включає CPU, мережу і диск з обох сторін.
Рішення: Порівняйте з розміром дельти і вікном RPO. Якщо вам потрібно 14G кожні 15 хвилин — 119MiB/s підходить; якщо потрібно 200G — це нереалістично.
Завдання 14: Визначити, чи вузьке місце — диск, CPU чи мережа
cr0x@dr1:~$ iostat -xz 1 3
avg-cpu: %user %nice %system %iowait %steal %idle
18.42 0.00 6.11 21.37 0.00 54.10
Device r/s rkB/s rrqm/s %rrqm r_await rareq-sz w/s wkB/s wrqm/s %wrqm w_await wareq-sz aqu-sz %util
nvme0n1 12.0 10240.0 0.0 0.00 1.20 853.3 410.0 92800.0 2.0 0.49 9.80 226.3 4.10 92.0
Що це означає: Високе %util і записове навантаження свідчать, що диск отримувача майже насичений. iowait значущий.
Рішення: Якщо диск завантажений, налаштування мережі не допоможе. Розгляньте швидші vdev-и, вирівнювання recordsize або проміжну передачу в швидший пул.
Завдання 15: Підтвердити lineage снапшотів (чому інкрементали падають)
cr0x@prod1:~$ zfs get -o name,property,value guid tank/prod/app@dr-2025-12-26_1100
NAME PROPERTY VALUE
tank/prod/app@dr-2025-12-26_1100 guid 1638672096235874021
cr0x@dr1:~$ zfs get -o name,property,value guid drpool/recv/tank/prod/app@dr-2025-12-26_1100
NAME PROPERTY VALUE
drpool/recv/tank/prod/app@dr-2025-12-26_1100 guid 1638672096235874021
Що це означає: GUID співпадає; приймач має точний екземпляр снапшота, необхідний для інкременталів.
Рішення: Якщо GUID-и відрізняються, ваш інкрементал не застосується. Потрібен новий повний send або виправлена ланцюжок реплікації.
Завдання 16: Перевірити властивості датасету, які можуть зламати відновлення (ACL, xattr, чутливість регістру)
cr0x@prod1:~$ zfs get -o name,property,value acltype,xattr,casesensitivity -r tank/prod/app
NAME PROPERTY VALUE
tank/prod/app acltype posixacl
tank/prod/app xattr sa
tank/prod/app casesensitivity sensitive
tank/prod/app/db acltype posixacl
tank/prod/app/db xattr sa
tank/prod/app/db casesensitivity sensitive
Що це означає: Встановлені властивості, що впливають на семантику додатка.
Рішення: Переконайтеся, що receive зберігає їх (реплікація властивостей) або що ви явно встановлюєте їх на відновленому датасеті. Невідповідність зберігання xattr може стати сюрпризом у продуктивності.
План швидкої діагностики: що перевірити першим/другим/третім
Під час тренування (або реального простою) конвеєр реплікації сповільнюється і люди одразу починають щось змінювати.
Не робіть цього. Діагностуйте у суворому порядку, щоб не «поправити» не той шар і не додати змінних.
По-перше: чи заблоковано це на пулі приймача?
- Перевірити:
zpool statusна предмет resilver/scrub;iostat -xzна предмет %util близького до 100% і високого await. - Інтерпретація: Якщо приймач зайнятий (resilver, scrub, проблеми SMR, насичені vdev-и), пропускна здатність receive падає незалежно від швидкості відправника.
- Дія: Призупиніть тренування, переплануйте навколо scrub/resilver або тимчасово отримуйте в швидший staging-пул.
По-друге: чи проблема в мережі або накладних SSH?
- Перевірити: спостережувана пропускна здатність з
pv; CPU на відправнику/приймачі; помилки NIC і втрати пакетів за допомогою системних інструментів. - Інтерпретація: Якщо CPU завантажений на одному ядрі під час SSH-шифрування — це ваша межа.
- Дія: Використовуйте швидші шифри, увімкніть апаратне прискорення там, де доступно, або реплікуйте по довіреній мережі альтернативним транспортом (залежно від політики). Не «оптимізуйте» безпеку в паніці.
По-третє: чи це поведінка на рівні ZFS (recordsize, стиснення, sync, спеціальні vdev-и)?
- Перевірити: властивості датасету, zvol проти filesystem, і чи навантаження — маленькі випадкові записи чи великі послідовні.
- Інтерпретація: DB-датасет з
recordsize=16Kповодиться інакше, ніж медіа-датасет зrecordsize=1M. - Дія: Вирівняйте recordsize і розгляньте розділення датасетів за типами навантаження. У DR шлях відновлення часто виявляє невідповідності, які ви ігнорували в продакшні.
По-четверте: чи це проблема ланцюжка реплікації?
- Перевірити: відсутні базові снапшоти, несумісність GUID або примусові відкатування, які обрізали потрібну історію.
- Інтерпретація: «Інкрементальний send падає» часто означає «історія снапшотів не така, якою ви її вважаєте».
- Дія: Припиніть експерименти з прапорами. Підтвердіть lineage, потім вирішіть: відновлювати з повного send або реконструювати очікуваний ланцюжок снапшотів.
Типові помилки: симптом → корінна причина → виправлення
1) Симптом: інкрементальний receive падає з «does not exist» або «incremental source … is not found»
Корінна причина: приймач не має точної базової миттєвої копії (неправильне ім’я, обрізано або інша GUID lineage після restore/rollback).
Виправлення: перелікуйте снапшоти обох сторін; порівняйте GUID-и; виконайте новий повний send, щоб відновити чистий ланцюжок. Уникайте ручного видалення снапшотів у дереві репліки на приймачі.
2) Симптом: receive «успішний», але датасети змонтувалися в продакшн-шляхи на хості DR
Корінна причина: отримані властивості mountpoint були застосовані, і zfs mount -a (або завантаження) змонтував їх.
Виправлення: отримуйте з -u; примусово встановіть mountpoint=none на дереві репліки; встановлюйте mountpoint-и тільки на відновлених клонах.
3) Симптом: тренування зупиняється на кроці «завантажити ключі» і ніхто їх не може знайти
Корінна причина: керування ключами шифрування було залишено «комусь одному», а не визначено як операційна залежність.
Виправлення: визначте опіку над ключами, місце зберігання та процедуру доступу; тестуйте завантаження ключів на кожному тренуванні; документуйте екстрений доступ з погодженням.
4) Симптом: пропускна здатність реплікації хороша вночі, але жахлива в робочі години
Корінна причина: спільні мережеві лінки, політика QoS, конкуренція за ресурси відправника/приймача або заплановані scrubs у пікові години.
Виправлення: вимірюйте пропускну здатність в піковий час; плануйте scrubs поза вікном реплікації; впровадьте формування трафіку за потреби; розгляньте staging-цілі або виділені лінки.
5) Симптом: «cannot receive: failed to read from stream» посеред трансферу
Корінна причина: розрив SSH-сеансу, невідповідність MTU, мережеві обриви або нестача місця, що спричиняє abort, який відображається як помилка стріму.
Виправлення: перевірте вільне місце на приймачі; перегляньте логи на предмет розривів; повторіть з моніторингом; використовуйте відновлювані стріми, якщо ваша версія ZFS їх підтримує, і тримайте запас місця.
6) Симптом: додаток стартує, але дані тонко неправильні або застарілі
Корінна причина: ви відновили невірний снапшот (неоднозначність іменування) або додаток потребує додаткового стану (WAL, об’єктне сховище, секрети), не покритого реплікацією датасетів.
Виправлення: впровадьте правила іменування та вибору снапшотів; додайте до обсягу DR залежності поза ZFS; перевіряйте справжньою бізнес-операцією під час тренування.
7) Симптом: receive повільний, CPU завантажений, а диски простоюють
Корінна причина: накладні витрати шифрування SSH, витрати на стиснення/декомпресію або однопотокове звуження в конвеєрі.
Виправлення: профілюйте CPU; змініть вибір шифру; розгляньте реплікацію по довіреній ізольованій мережі з відповідним транспортом; уникайте бездумного складання стиснення в кілька шарів.
8) Симптом: відновлення вдалося один раз, але наступні тренування стають більш заплутаними й повільними
Корінна причина: хост DR перетворився на шухляду напіввідновлених датасетів, змонтованих шляхів і змінених реплік; «ще одне швидке виправлення» перетворилося на стан.
Виправлення: ставтеся до DR-середовища як до коду: відтворюйте або скидайте між тренуваннями; тримайте репліки в режимі read-only; відновлюйте через клон і видаляйте після тренування.
Три корпоративні міні-історії з реального світу
Міні-історія 1: Інцидент через неправильне припущення
Середня компанія мала два сайти і акуратну налаштування реплікації ZFS. Продакшн відправляв погодинні снапшоти на DR-хост.
Команда була впевнена, бо логи receive показували «success» місяцями.
Потім проблема контролера знищила первинний пул. Не катастрофа — саме для цього потрібен DR.
Вони підняли датасет на DR і спробували запустити сервіси. Файлова система змонтувалася. Додаток стартував. База даних відмовила.
Неправильне припущення: «Реплікуємо датасет додатка, отже реплікуємо всю систему.» Насправді журнали бази даних жили в окремому датасеті, доданому пізніше.
Він не був включений у задачу реплікації. Ніхто цього не помітив, бо під час реплікації нічого не падало; просто мовчки була пропущена нова залежність.
Під час аварії хтось спробував «вирішити» копіюванням відсутнього датасета зі старого VM-резервного копіювання. База піднялася, але з хибною тимчасовою лінією.
Тепер сервіс працював, але логічно був неконсистентний — гірше за просто недоступність, бо сумнів у правильності даних.
Пост-інцидентне покращення було не складним: інвентаризація датасетів по сервісах, перевірки покриття реплікацією і DR-тренування з вимогою реального кінцевого шляху запису.
Урок не в тому, що ZFS підвів. Урок у тому, що наша ментальна модель провалилася, а ZFS цього не завадив.
Міні-історія 2: Оптимізація, яка обернулася проти
Інша організація хотіла швидшу реплікацію. Хтось помітив CPU-навантаження під час SSH-реплікації і вирішив оптимізувати.
Вони змінили конвеєр, додали додаткове стиснення і підкоригували кілька прапорів. У швидкому тесті все виглядало чудово: менші стрими, вищий піковий throughput.
Через місяць receives на DR почали відставати у пікові години. Не на хвилини — на години. Черга реплікацій зростала.
Команда переслідувала мережу, потім диски, потім планувальник.
Наслідок: додатковий шар стиснення зробив відправника CPU-зв’язаним у реальному навантаженні і підвищив варіативність латентності.
Тести робилися на простої системі з «теплим» ARC, а не в реальному хаосі продакшн-записів.
Реплікація стала крихкою: іноді швидкою, іноді крижаною, завжди непередбачуваною.
Виправлення було майже прикрим: прибрати зайвий шар стиснення, покластися на нативне стиснення ZFS і вимірювати на репрезентативному навантаженні.
Також обмежили паралелізм і запланували реплікацію так, щоб не конфліктувати зі scrub-вікнами.
Найкраща оптимізація — та, яку можна пояснити наступному черговому у дві речення. Якщо для цього потрібна дошка і молитва — це не оптимізація, а риса характеру.
Міні-історія 3: Нудна, але правильна практика, яка врятувала ситуацію
Фінансова команда мала репутацію надміру методичної. Вони проводили квартальні DR-тренування з чеклістом, мітками часу і звичкою видаляти й відтворювати DR-restore датасети щоразу.
Це не було гламурно, тому їх часто кепкували команди, які обирали «інновації».
Реальний інцидент стався під час планового вікна обслуговування: інженер виконав destroy датасета на неправильному хості.
Це типова помилка, коли середовище схоже, а кількість вкладок терміналу перевищує увагу.
Команда DR не імпровізувала. Вони слідували раннбуку: знайти останній хороший снапшот на приймачі, клонувати в простір відновлення, завантажити ключі, змонтувати, запустити сервіси, провести smoke-тести.
Оскільки вони практикували ті самі команди регулярно, ніхто не сперечався, який снапшот використовувати або куди ставити mountpoint-и.
Відновлення не було миттєвим, але було контрольованим. Найважливіше — вони не заразили репліку хакерськими виправленнями, щоб «запустити все».
Репліка залишилася джерелом істини, а відновлений клон був одноразовим.
Пізніше керівництво називало це «вдачею». Це не була удача. Це була нудна звичка, яка не дозволила людям погіршити ситуацію.
Чеклісти / покроковий план
Чекліст проєктування тренування (до дня тренування)
- Виберіть один сервіс і перелічіть усі датасети, від яких він залежить (дані, БД, логи, конфігурації, секрети за потреби).
- Визначте цілі RPO і RTO у хвилинах/годинах, а не «на око».
- Вирішіть цільовий простір імен для відновлення (
drpool/recvдля реплік,drpool/restoreдля записуваних відновлень). - Визначте метод керування ключами для зашифрованих датасетів; перевірте шляхи доступу для чергового.
- Визначте конвенцію іменування снапшотів для DR (наприклад,
dr-YYYY-MM-DD_HHMM). - Узгодьте, що означає «сервіс відновлено»: smoke-тести, синтетична транзакція або конкретні health-endpoint-и.
- Заплануйте тренування у реалістичне навантаження хоча б раз на рік (пікове навантаження виявляє проблеми).
Чекліст готовності реплікації (у день тренування, перед стартом)
- Пули відправника і приймача здорові (
zpool status -x). - Приймач має достатньо вільного місця для снапшотів + запас.
- Репліки за замовчуванням незмонтовані (політика
-u,mountpoint=none). - Підтверджено наявність і свіжість снапшотів з обох сторін.
- Підтверджено політику відкату (
zfs receive -Fприйнятний чи ні для цієї репліки).
План виконання відновлення (тренування)
- Оголосіть час початку тренування. Запишіть його. DR без міток часу — це лише інсценізація.
- Виберіть снапшот. Використайте найновіший снапшот, що фактично присутній на DR і відповідає вашому RPO.
- Створіть restore-клон. Ніколи не відновлюйте шляхом модифікації дерева репліки напряму, якщо не любите ризики.
- Встановіть mountpoint-и явно. Уникайте успадкованих отриманих mountpoint-ів; вони оптимізовані для сюрпризів.
- Завантажте ключі (якщо зашифровано). Підтвердіть
keystatus=available. - Монтуйте датасети в правильному порядку. БД перед додатком, якщо сервіс цього очікує.
- Запустіть сервіси. Використовуйте стандартні команди service manager і зберіть логи.
- Виконайте smoke-тести. Одна реальна операція запису, один шлях читання, один запит або один вхід користувача.
- Зафіксуйте RTO. Припиніть відлік часу, коли сервіс пройшов критерії тесту, а не коли змонтувався датасет.
- Очистіть. Видаліть restore-клони і тимчасові mountpoint-и; збережіть репліку недоторканою.
- Запишіть несподіванки. Це і є головна мета.
Жарт #2: Тренування DR — єдина зустріч, де «нам треба все знищити й почати знову» одночасно правильна і заохочувана.
Питання й відповіді
1) Чи є реплікація ZFS резервною копією?
Вона може бути частиною стратегії резервного копіювання, але сама по собі часто дзеркалить ваші помилки. Якщо рансомвар шифрує файли і ви швидко реплікуєте ці зміни,
вітаю: у вас дві копії проблеми. Вам все ще потрібні ретеншен, механізми незмінності і бажано принаймні одна офлайн або логічно ізольована копія.
2) Чи варто приймати прямо в кінцеві mountpoint-и?
Для DR-тренувань — ні. Отримуйте в інертний простір імен з -u і нейтральними mountpoint-ами, потім клонувати в простір відновлення з явними mountpoint-ами.
Це знижує ризик змонтувати поверх важливого або запустити сервіси проти невірного датасета.
3) Коли підходить zfs receive -F?
Коли приймач є чистою реплікою і ви погоджуєтеся відкочувати його, щоб прийняти потік.
Неприйнятно, якщо на приймачі є локальні зміни, які вам важливі, або коли ви не розумієте, чому це потрібно.
4) Як обрати, який снапшот відновлювати?
Використовуйте найновіший снапшот, що фактично присутній на приймачі й відповідає вашому RPO. Потім перевіряйте цілісність додатка.
Іменування снапшотів має кодувати призначення (DR проти ad-hoc), щоб «latest» випадково не означав «експеримент когось».
5) Щодо зашифрованих датасетів — чи потрібні ключі на DR-хості?
Якщо ви надсилаєте raw зашифровані стріми (zfs send -w), приймач може зберігати зашифровані дані без ключів, але не зможе змонтувати їх до завантаження ключів.
Вирішіть, чи ключі зберігаються на DR (швидше) або отримуються під час інциденту (безпечніше). Відпрацюйте обидва варіанти.
6) Чи варто реплікувати властивості з -p?
Іноді. Реплікація властивостей може зберегти важливу поведінку (стискання, recordsize, ACL), але також може принести mountpoint-и й локальні конвенції, яких ви не хочете.
Звичайна компромісна практика: реплікувати більшість властивостей, але застосовувати політику mountpoint-ів на приймачі й відновлювати через клон.
7) Чому мій receive повільний, коли відправник швидкий?
Тому що продуктивність receive зазвичай обмежена приймачем: IOPS запису диска, фрагментація, scrubs/resilver-и і CPU для контрольних сум/декомпресії.
Виміряйте кінцеву пропускну здатність і потім спочатку дивіться iostat і активність пулу приймача.
8) Чи потрібно тестувати відновлення, якщо логи реплікації показують успіх?
Так. Логи кажуть «стрім застосовано». Вони не кажуть «сервіс відновлюваний», «ключі можна завантажити», «mountpoint-и безпечні» або «RTO досяжний».
DR-тренування виявляють операційні розриви, а не баги файлової системи.
9) Як часто треба проводити DR-тренування?
Щоквартально, якщо можете; піврічно, якщо доводиться; щорічно — лише якщо ваше середовище змінюється повільно (воно не змінюється повільно).
Проведіть принаймні одне тренування на рік у реалістичному навантаженні і частіші «настільні» вправи при зміні ключового персоналу або архітектури.
10) Чи має DR-хост бути ідентичним апаратно як продакшн?
Не обов’язково, але вам потрібна передбачуваність продуктивності. Якщо DR набагато повільніший, ваш RTO зросте.
Якщо DR використовує інші дискові конфігурації або мережеві шляхи, тренування повинні вимірювати реальну швидкість відновлення, а не теоретичну.
Висновок: наступні кроки, які можна запланувати цього тижня
Якщо ви «перевіряєте резервні копії», дивлячись лише на наявність снапшотів, ви перевіряєте паперову роботу. ZFS send/receive потужний, але не магічний.
Шлях відновлення — це місце, де дизайн системи зустрічається з людською реальністю: іменування, доступ до ключів, mountpoint-и і тиск часу.
Практичні наступні кроки:
- Виберіть один сервіс і зробіть інвентар його датасетів і залежностей поза ZFS.
- Визначте RPO/RTO і запишіть, що означає «завершено» на рівні додатка.
- Побудуйте безпечний простір отримання з незмонтованими репліками і нейтральними mountpoint-ами.
- Проведіть одне повне відновлення через клон і явне завантаження ключів.
- Зафіксуйте часи і вузькі місця, потім усуньте найбільше з них — ємність, ключі або пропускну здатність.
- Повторюйте, поки тренування не стане нудним. Нудність — це надійність.