ZFS: Репліка, яку ви вважали справжньою — як по-справжньому аудитувати реплікацію

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

Реплікація здається нудною лише тоді, коли вона працює. Коли ні — це повільний фільм жахів:
CEO питає «У нас є копія?» і ви відповідаєте «Так», а в цей час ваш шлунок тихо оголошує дефолт.

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

Що означає «справжня реплікація» в продакшні

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

  • Достатньо актуальна: ваш RPO підтверджується спостереженням, а не оптимізмом.
  • Цілісна: походить від узгодженої ланцюжка снапшотів, а не відштопаного випадку.
  • Повна: всі потрібні вам датасети включені (включно з дочірніми, властивостями та утриманнями, якщо актуально).
  • Розшифровувана: якщо використовується шифрування, ви дійсно можете завантажити ключі й змонтувати під час найгіршого дня року.
  • Відновлювана: ви можете промотити, відкотити, змонтувати і передати результат додатку без археології.
  • Операційно безпечна: реплікація не саботує продакшн через піки навантаження, гігантські снапшоти чи зворотний тиск.

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

Ось керівне правило: аудитуйте шлях відновлення, а не шлях відправки. Відправляти дані легко.
Відновити їх під тиском — ось де ваші неперевірені припущення гинуть.

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

Парафраз idea від John Allspaw (operations/reliability): надійність приходить від навчання у брудному реальному світі, а не від віри в план.
Аудит реплікації — це той цикл навчання, застосований до зберігання.

Цікаві факти та історичний контекст

  1. ZFS спроєктовано навколо контрольних сум «end-to-end» (дані й метадані), що дає змогу виявляти мовчазну корупцію — якщо ви виконуєте scrub та моніторинг.
  2. Снапшоти в ZFS дешеві тому, що це посилання copy-on-write, а не повні копії. Проте вони можуть стати дорогими, якщо зберігати їх вічно.
  3. Оригінальний ZFS з’явився в Sun Microsystems; його підхід до реплікації (send/receive) був створений для безпечного та детермінованого перенесення дельт снапшотів.
  4. OpenZFS став крос-платформовим проєктом після занепаду Sun, і сумісність функцій змінюється в залежності від дистрибутива та версії ОС — це важливо для resume tokens і поведінки шифрування.
  5. Потоки реплікації можуть включати властивості датасетів в залежності від прапорів; відсутні властивості — класична помилка «відновилося, але неправильно».
  6. Resume tokens існують тому, що довгі send-и ламаються у реальних мережах. Вони не для краси; вони рятують від повторної відправки 40 TB після 3-секундного обриву лінку.
  7. Шифрування в ZFS — на рівні датасету, а не пулу, і управління ключами на приймачі — окрема операційна задача.
  8. Scrub-и — не бекапи, але вони — інструмент аудиту: показують, чи репліка може читати власні дані надійно.

Модель аудиту, що ловить типові брехні

Брехня №1: «Репліка існує» (але це не потрібні датасети)

Ви реплікували tank/data, але не tank/data/mysql, бо хтось створив його пізніше
і ваш скрипт перерахував датасети одного разу в 2022 і більше ніколи. Приймач виглядає здоровим. Відновлення — порожній погляд.
Ваш аудит має порівнювати «що повинно бути захищене» і «що захищене» та помічати дрейф.

Брехня №2: «Воно актуальне» (але план створення снапшотів зламався)

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

Брехня №3: «Воно цілісне» (але ланцюжок розірваний)

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

Брехня №4: «Воно відновлюване» (але приймач непридатний у DR)

Приймач може бути лише для читання, може мати canmount=off, може потребувати ключів шифрування, може вимагати промоуту клонів,
може не мати очікуваних точок монтування або може відновитися з неправильними властивостями recordsize/compression і зруйнувати продуктивність.
Реальний аудит включає недеструктивний тест відновлення на стенді й документований runbook «promote і mount».

Брехня №5: «У нас є пропускна здатність» (але часу у вас немає)

Реплікація може «завершитися зрештою», але при цьому не відповідати RPO і RTO, бо дельта росла швидше, ніж лінк її переносить.
Аудит означає вимірювання розмірів send-ів, швидкостей receive і росту снапшотів з часом. Ніяких здогадок. Ніякого «має бути добре».

Жарт №1: Плани реплікації як парасольки — всі про них згадують саме коли починає падати дощ.

План швидкої діагностики

Це послідовність «зараз 02:13, і реплікація відстає». Мета — знайти вузьке місце за хвилини, а не години.
Перевіряйте пункти в порядку; зупиняйтесь, коли знайдете перше жорстке обмеження.

Перше: Чи є що реплікувати?

  • Чи запускається створення снапшотів на відправнику?
  • Чи найновіший снапшот на відправнику новіший за найновіший на приймачі?
  • Чи не застрягли ви через відсутній спільний снапшот (зламаний інкрементальний ланцюжок)?

Друге: Чи процес реплікації справді передає дані?

  • Чи запущено zfs receive і чи він споживає стрім?
  • Чи застрягли ви на resume token?
  • Чи мережа насичена або нестабільна?

Третє: Чи приймач здатний записувати?

  • Стан пулу: degraded, suspended або недостатньо місця?
  • Затримки IOPS: чи диски задухають або відсутній/неправильно використовується SLOG?
  • Чи йде інтенсивний scrub/resilver, що конкурує з реплікацією?

Четверте: Чи відправник є вузьким місцем?

  • Навантаження через стиснення/шифрування під час send?
  • Великі дельти снапшотів через помилки ретеншну?
  • Розташування датасетів (recordsize, sync), що викликає патологічний IO?

П’яте: Чи ви втрачаєте час на уникненні переробок?

  • Чи випадково виконуєте full send, бо базовий снапшот не співпадає?
  • Чи не використовуєте resume tokens через ненадійні лінки?
  • Чи повторно відправляєте властивості і примушуєте зайвий churn?

Практичні завдання аудиту (команди, виводи, рішення)

Це не «приємно знати». Це команди, які ви виконуєте, коли хочете перестати вірити й почати знати.
Припустимо, що хост відправник zfs-prod-01 з пулом tank, а приймач zfs-dr-01 з пулом backup.

Завдання 1: Підтвердити стан пулу з обох боків

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

Що це означає: жодних відомих помилок, жодних деградованих vdev, жодних призупинених IO.
Якщо ви бачите щось інше, коректність реплікації другорядна порівняно з виживанням пулу.
Рішення: Якщо не здоровий, призупиніть агресивну реплікацію і виправте пул спочатку; деградований приймач може непомітно подовжити RTO.

Завдання 2: Перевірити, чи на приймачі достатньо вільного місця для найгірших дельт

cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint backup
NAME    USED  AVAIL  REFER  MOUNTPOINT
backup  62.1T 8.40T   128K  /backup

Що це означає: лише 8.4T вільно. Якщо наступна дельта буде 10T через помилку ретеншну, receive зазнає фейлу посеред потоку.
Рішення: Встановіть політику «мінімального вільного місця» (жорстку) і сповіщення. Якщо нижче порога — обрізайте снапшоти або збільшуйте ємність перед наступним великим send-ом.

Завдання 3: Перелічити те, що ви вважаєте реплікованим (відправник)

cr0x@server:~$ zfs list -r -o name,type,mountpoint tank/data
NAME                 TYPE  MOUNTPOINT
tank/data            filesystem  /tank/data
tank/data/mysql      filesystem  /tank/data/mysql
tank/data/pg         filesystem  /tank/data/pg
tank/data/home       filesystem  /tank/data/home

Що це означає: це ваш цільовий охват. Інструменти реплікації повинні охоплювати все це (або явно виключати частини).
Рішення: Якщо ваші скрипти реплікують лише фіксований список, замініть їх на рекурсивне виявлення датасетів плюс allow/deny правила в системі контролю версій.

Завдання 4: Перелічити те, що реально існує на приймачі

cr0x@server:~$ zfs list -r -o name,type,mountpoint backup/data
NAME                 TYPE  MOUNTPOINT
backup/data          filesystem  /backup/data
backup/data/mysql    filesystem  none
backup/data/home     filesystem  none

Що це означає: backup/data/pg відсутній. Також mountpoint-и встановлені в none (можливо, це навмисно для DR).
Рішення: Відсутні датасети — це справа, яка зупиняє роботу. Виправте обсяг реплікації перед тим, як сперечатися про продуктивність.

Завдання 5: Перевірити часи створення найновіших снапшотів на відправнику і приймачі (реальність RPO)

cr0x@server:~$ zfs list -t snapshot -o name,creation -s creation -r tank/data/mysql | tail -n 3
tank/data/mysql@rep_2026-02-04_0000  Tue Feb  4 00:00 2026
tank/data/mysql@rep_2026-02-04_0030  Tue Feb  4 00:30 2026
tank/data/mysql@rep_2026-02-04_0100  Tue Feb  4 01:00 2026
cr0x@server:~$ zfs list -t snapshot -o name,creation -s creation -r backup/data/mysql | tail -n 3
backup/data/mysql@rep_2026-02-04_0000  Tue Feb  4 00:00 2026
backup/data/mysql@rep_2026-02-04_0030  Tue Feb  4 00:30 2026
backup/data/mysql@rep_2026-02-04_0100  Tue Feb  4 01:00 2026

Що це означає: приймач збігається з відправником до 01:00. RPO для цього датасету наразі — «хвилини», а не «можливо».
Рішення: Відстежуйте це автоматично. Якщо найновіший снапшот приймача відстає за політикою — сповістіть on-call. Саме для цього це і потрібно.

Завдання 6: Підтвердити, що базовий інкрементальний снапшот існує на обох сторонах

cr0x@server:~$ zfs list -t snapshot -o name -r tank/data/mysql | grep rep_2026-02-03_2300
tank/data/mysql@rep_2026-02-03_2300
cr0x@server:~$ zfs list -t snapshot -o name -r backup/data/mysql | grep rep_2026-02-03_2300
backup/data/mysql@rep_2026-02-03_2300

Що це означає: спільна база існує. Якщо ні — наступний send з -i зазнає помилки «incremental source does not exist».
Рішення: Якщо база відсутня, оберіть між (a) відновленням відсутнього снапшоту (якщо доступний), (b) виконанням повного send, або (c) відбудовою датасету на приймачі.

Завдання 7: Виявити несподівані full send-и, оцінюючи розмір дельти

cr0x@server:~$ zfs send -nPv -i tank/data/mysql@rep_2026-02-04_0000 tank/data/mysql@rep_2026-02-04_0100
size	2.31G
incremental	tank/data/mysql@rep_2026-02-04_0000	tank/data/mysql@rep_2026-02-04_0100
no-op bytes	132K

Що це означає: очікувана дельта — ~2.31G. Якщо ви виконаєте це і побачите «size 4.8T», вам прийдеться серйозно переглянути віру.
Рішення: Якщо розмір дельти значно перевищує норму, зупиніть і розслідуйте ретеншн, файли, що розрослися, або зламаний інкрементальний ланцюжок, перш ніж ви заб’єте лінк на дні.

Завдання 8: Перевірити resume tokens на приймачі (застрягла реплікація)

cr0x@server:~$ zfs get -H -o name,value receive_resume_token backup/data/mysql
backup/data/mysql	1-EMyVd...AAAB

Що це означає: токен існує: прийом було перервано. Ваша автоматизація може сліпо запускати нові send-и, які не прикріпляться.
Рішення: Або відновіть стрім за допомогою токена, або явно скасуйте і очистіть стан (обережно). Розглядайте токени як журнал транзакцій, а не мотлох.

Завдання 9: Безпечно відновити перерваний send

cr0x@server:~$ TOKEN=$(zfs get -H -o value receive_resume_token backup/data/mysql)
cr0x@server:~$ ssh zfs-prod-01 "zfs send -t $TOKEN" | zfs receive -s -F backup/data/mysql
cr0x@server:~$ echo $?
0

Що це означає: код виходу 0: відновлений receive завершився успішно.
Рішення: Додайте логіку, що розпізнає токени, до вашого інструменту реплікації. Якщо ваш процес цього не підтримує, ви на одному ненадійному лінку від повторення терабайтів.

Завдання 10: Перевірити відтворення властивостей (перевірка «відновилося, але неправильно»)

cr0x@server:~$ zfs get -H -o name,property,value compression,recordsize,atime,canmount tank/data/mysql
tank/data/mysql	compression	zstd
tank/data/mysql	recordsize	16K
tank/data/mysql	atime	off
tank/data/mysql	canmount	on
cr0x@server:~$ zfs get -H -o name,property,value compression,recordsize,atime,canmount backup/data/mysql
backup/data/mysql	compression	zstd
backup/data/mysql	recordsize	128K
backup/data/mysql	atime	on
backup/data/mysql	canmount	noauto

Що це означає: приймач відрізняється: recordsize і atime не збігаються, а canmount навмисно інший.
Невідповідність recordsize може зруйнувати продуктивність бази даних після failover.
Рішення: Визначте властивості, що мають співпадати для DR. Реплікуйте їх навмисно (або застосовуйте політику після отримання).
Не «оптимізуйте» репліку так, щоб вона стала непридатною.

Завдання 11: Підтвердити стан шифрування й доступність ключів (не відкривайте це під час DR)

cr0x@server:~$ zfs get -H -o name,property,value encryption,keystatus,keylocation tank/secure/hr
tank/secure/hr	encryption	aes-256-gcm
tank/secure/hr	keystatus	available
tank/secure/hr	keylocation	prompt
cr0x@server:~$ zfs get -H -o name,property,value encryption,keystatus,keylocation backup/secure/hr
backup/secure/hr	encryption	aes-256-gcm
backup/secure/hr	keystatus	unavailable
backup/secure/hr	keylocation	prompt

Що це означає: на приймачі дані зашифровані, але ключ не завантажено. Це може бути правильним (з точки зору безпеки), але має бути операційно спланованим.
Рішення: Впровадьте процес ескроу ключів і runbook для завантаження ключів у DR. Якщо ніхто не може завантажити ключі о 03:00, у вас немає репліки.

Завдання 12: Виконати недеструктивний тест монтовання на приймачі (довести шлях відновлення)

cr0x@server:~$ zfs clone backup/data/mysql@rep_2026-02-04_0100 backup/test-restore/mysql
cr0x@server:~$ zfs set canmount=noauto mountpoint=/mnt/restore-mysql backup/test-restore/mysql
cr0x@server:~$ zfs mount backup/test-restore/mysql
cr0x@server:~$ zfs list -o name,mountpoint backup/test-restore/mysql
NAME                     MOUNTPOINT
backup/test-restore/mysql /mnt/restore-mysql

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

Завдання 13: Перевірити цілісність даних через scrub-статус на приймачі

cr0x@server:~$ zpool status backup
  pool: backup
 state: ONLINE
  scan: scrub repaired 0B in 05:14:02 with 0 errors on Sun Feb  2 03:12:44 2026
config:

	NAME        STATE     READ WRITE CKSUM
	backup       ONLINE       0     0     0
	  raidz2-0   ONLINE       0     0     0
	    sda     ONLINE       0     0     0
	    sdb     ONLINE       0     0     0
	    sdc     ONLINE       0     0     0
	    sdd     ONLINE       0     0     0

Що це означає: scrub завершився з нульовими помилками. Це доказ того, що ваша репліка може прочитати власні блоки.
Рішення: Якщо scrub показує помилки, вважайте приймач підозрілим до виправлення; реплікація на пошкоджені носії — не «безпека».

Завдання 14: Шукати дрейф ретеншну снапшотів (відправник і приймач мають узгоджуватись)

cr0x@server:~$ zfs list -t snapshot -o name -r tank/data/mysql | wc -l
336
cr0x@server:~$ zfs list -t snapshot -o name -r backup/data/mysql | wc -l
92

Що це означає: на приймачі набагато менше снапшотів. Можливо, навмисно. Можливо, хтось виконує cleanup тільки на DR і зламав інкрементальний ланцюжок.
Рішення: Узгодьте політику ретеншну з методом реплікації. Якщо ви чистите на приймачі, потрібно зберегти базові снапшоти, потрібні для інкременталів.

Завдання 15: Перевірити, чи реплікація не конкурує з resilver/scrub у невдалий час

cr0x@server:~$ zpool iostat -v backup 5 2
                              capacity     operations     bandwidth
pool                        alloc   free   read  write   read  write
--------------------------  -----  -----  -----  -----  -----  -----
backup                      62.1T  8.40T    120    980   9.2M  112M
  raidz2-0                  62.1T  8.40T    120    980   9.2M  112M
    sda                         -      -     30    240   2.3M   28M
    sdb                         -      -     28    260   2.1M   29M
    sdc                         -      -     32    250   2.4M   28M
    sdd                         -      -     30    230   2.4M   27M

Що це означає: записи інтенсивні; якщо затримки також високі, receive може повзти. Якщо ви бачите scrub/resilver, очікуйте погіршення.
Рішення: Плануйте вікна реплікації або обмежуйте швидкість send, коли пул вже зайнятий роботою з відновлення.

Завдання 16: Визначити, які снапшоти тримають місце (чому дельти великі)

cr0x@server:~$ zfs holds -r tank/data/mysql@rep_2026-02-01_0000
NAME                                  TAG     TIMESTAMP
tank/data/mysql@rep_2026-02-01_0000    keep    Sun Feb  1 00:00 2026

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

Жарт №2: Resume token — як та шафка з таємничними кабелями: марний, поки раптом не стає єдиним, що рятує ваш уїкенд.

Три корпоративні міні-історії (як це ламається)

1) Інцидент через неправильне припущення: «Реплікація успішна, бо job сказав OK»

Середня компанія виконувала ZFS реплікацію з продакшну до DR-сайту. Job реплікації був акуратним shell-скриптом
під cron. Він писав логи. Він навіть надсилав email «success», якщо pipeline повернув нульовий код.
Всі спали спокійно. Занадто спокійно.

Підказка: снапшоти створював інший job на продакшн-хості. Той job перестав працювати мовчки після оновлення пакету,
який змінив шлях у скрипті. Реплікація продовжувала працювати, не знайшла нових снапшотів і виконала нуль роботи — чисто.
Логи показували успішні прогони, бо send крок коректно нічого не відправляв, а receive коректно нічого не приймав.

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

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

2) Оптимізація, що відкотилася: «Зменшимо кількість снапшотів на DR, щоб заощадити місце»

Інша організація мала тісний DR-пул. Хтось подивився на кількість снапшотів і вирішив, що на DR їх можна зменшити.
Хост DR виконував політику очищення, яка видаляла старі снапшоти агресивніше, ніж на продакшні.
На папері це було ефективно: менше снапшотів, менше місця, менше метаданих.

Потім інкрементали почали періодично падати. Інструмент реплікації намагався надіслати від останнього спільного снапшоту,
але цей снапшот був видалений на приймачі. Інструмент відповів fallback-ом до повного send — бо автор скрипта думав «краще реплікувати повільно, ніж падати».
Це працювало, поки не перестало.

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

Остаточне рішення: уніфікувати логіку ретеншну між відправником і приймачем і явно захищати останні N снапшотів на приймачі за допомогою holds,
щоб інкрементали завжди мали базу. Команда також перестала дозволяти автоматичний fallback до full send без гучного оповіщення і людського рішення.

3) Нудна, але правильна практика, що врятувала день: «Щоквартальні вправи з відновлення на стенді»

Регульований бізнес мав звичку, над якою інженери спочатку глузували:
кожного кварталу вони виконували відновлювальну вправу. Не tabletop — реальне відновлення на стенд, з тією ж сімейство ОС,
тими самими ZFS feature flags і спрощеною версією додатку.

Чекліст вправи був простим. Підтвердити, що найновіший снапшот існує. Клонувати його. Змонтувати. Запустити легку перевірку цілісності.
Запустити сервіс, спрямований на відновлений датасет. Перевірити базову поведінку додатку. Задокументувати час виконання.
Потім знищити клон. Без героїзму, без «запам’ятаємо пізніше».

Коли вони пізніше зазнали інциденту з ransomware у продакшні, storage-команда не вигадувала план відновлення на ходу.
Вони вже мали мускульну пам’ять: «знайти останній known-good снапшот, клонувати на DR, при необхідності промотити, підняти сервіс».
Відновлення все ще не було приємним — нічого не приємне під час ransomware — але воно було виконуваним.

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

Типові помилки (симптом → причина → виправлення)

Реплікація «успішна», але дані в DR застарілі

  • Симптом: jobs повідомляють успіх; найновіший снапшот на приймачі застарілий на години/дні.
  • Причина: створення снапшотів зупинилося; реплікація працювала без нових снапшотів; немає перевірки RPO.
  • Виправлення: налаштуйте оповіщення за «віком найновішого снапшоту по датасету» і «віком найновішого реплікованого снапшоту». Вважайте «немає нових снапшотів» помилкою, якщо це не очікувано.

Інкрементальні send-и падають: «does not exist» або «incremental source» помилки

  • Симптом: помилки send/receive про відсутні снапшоти; автоматизація намагається вічно.
  • Причина: приймач обрізав снапшоти або ніколи не отримував базу; невідповідність імен; реплікація почалася посеред ланцюжка.
  • Виправлення: забезпечте симетрію ретеншну для «вікна бази»; використовуйте holds на приймачі для необхідних базових снапшотів; відновіть датасет повним send-ом, коли ланцюжок безповоротно зламано.

Реплікація повільна, незважаючи на достатню пропускну здатність

  • Симптом: мережа не насичена, але receive повільний; затримки пулу високі.
  • Причина: приймачеві диски — вузьке місце; конкуренція зі scrub/resilver; маленький recordsize датасетів, що потребують багато IOPS.
  • Виправлення: плануйте або обмежуйте реплікацію під час відновлення; вимірюйте за допомогою zpool iostat; розгляньте налаштування властивостей на продакшні (обережно), а не «виправлення» DR поодинці.

Репліка монтується, але продуктивність додатку погана після failover

  • Симптом: DR-сервіс стартує, але повільний; метрика БД показує повільність.
  • Причина: властивості розійшлись (recordsize, compression, atime, logbias); реплікація не включала властивості або приймач застосував інші значення за замовчуванням.
  • Виправлення: визначте набір властивостей «мають збігатись»; реплікуйте властивості навмисно; перевіряйте через періодичні diff-и властивостей і вправи з відновлення.

Зашифровані датасети реплікуються, але DR не може їх змонтувати

  • Симптом: датасети існують на DR; keystatus=unavailable; монтування фігурує під час інциденту.
  • Причина: управління ключами не інтегроване в DR; ключі вимагають ручного введення від людини, яка спить або недоступна.
  • Виправлення: встановіть ескроу ключів і процедуру break-glass; тестуйте завантаження ключів у DR щоквартально; перевіряйте сумісність feature flags.

Реплікація випадково перезапускається з нуля

  • Симптом: великі передачі повторюються; час job зростає; рахунки WAN цікавішають.
  • Причина: перервані стріми без resume; resume tokens ігноруються; автоматизація запускає нові повні send-и.
  • Виправлення: використовуйте zfs receive -s і логіку відновлення по токенах; сповіщайте, коли receive_resume_token існує довше встановленого порога; уникайте «тихого fallback до full».

Реплікація виглядає нормально, але ієрархія датасетів на DR неправильна

  • Симптом: деякі дочірні відсутні; mountpoint-и дивні; квоти/резерви відсутні.
  • Причина: скрипт реплікації не використовував рекурсію; датасети, створені пізніше, ніколи не додали; властивості не включені.
  • Виправлення: реплікуйте рекурсивно з явними виключеннями; перевіряйте дрейф списку датасетів; забезпечте очікувану ієрархію за допомогою файлу «бажаного стану».

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

Щотижневий аудит (15–30 хвилин)

  1. Стан пулу: перевірити zpool status -x на відправнику і приймачі; будь-який не-здоровий стан — пріоритет.
  2. Перевірка RPO: порівняти часи найновіших снапшотів на обох сторонах для критичних датасетів (БД, домашні директорії, об’єктні сховища).
  3. Перевірка охвату: переконатися, що дерево датасетів відповідає тому, що ви вважаєте захищеним; шукати нові дочірні, які не покриті.
  4. Перевірка ретеншну: порівняти кількість снапшотів і переконатися, що базові снапшоти потрібні для інкременталів існують на приймачі.
  5. Перевірка resume token-ів: впевнитися, що немає довгоживучих receive_resume_token без дій.
  6. Перевірка ємності: підтвердити вільний простір приймача відносно найгіршого сценарію дельти і запасу безпеки.

Щомісячний аудит (1–2 години)

  1. Diff властивостей: вибірково перевіряти критичні датасети і порівнювати властивості, що впливають на поведінку в runtime (recordsize, compression, atime, sync, logbias, quotas).
  2. Огляд scrub-ів: підтвердити, що scrub на приймачі завершився з нульовими помилками; негайно розслідувати checksum чи read помилки.
  3. Оцінка розмірів дельт: виконати zfs send -nPv для кількох репрезентативних інкременталів і зафіксувати розміри; стежити за різкими стрибками.
  4. Ін’єкція відмови: навмисно перервати реплікацію і підтвердити, що логіка resume token працює.

Щоквартальна вправа відновлення (півдня, але воно окупається)

  1. Вибір датасету: виберіть один цінний датасет (БД або важлива шарка файлів) і один «широкий» датасет (багато дрібних файлів).
  2. Клонувати найновіший снапшот на DR: змонтувати його у контрольованому шляху.
  3. Валідація на рівні додатку: запустити мінімальний старт сервісу або перевірку цілісності, що нагадує реальність.
  4. Заміряти час: зафіксуйте, скільки зайняв кожен крок; це ваша доказова база RTO.
  5. Видалити клони: прибрати; упевнитися, що вправа не роздуває простір на тижні.
  6. Оновити runbook: якщо хтось «повинен був знати», запишіть це у процедуру.

Жорсткі правила (ті, що запобігають нічному 03:00 обговоренню)

  • Ніяких тихих full send-ів. Якщо інкрементали падають і ви обираєте full — це людське рішення з оповіщенням.
  • Ніякої реплікації без моніторингу RPO. «Job succeeded» — саме по собі марна метрика.
  • Ніякого шифрування без DR-процедур по ключах. «Безпечно, але невідновлювано» — це форма втрати даних.
  • Ніякого обрізання на приймачі, що ламає ланцюжки. Якщо потрібно обрізати — збережіть базові снапшоти, потрібні для інкременталів.

FAQ

1) Яка найважливіша метрика для здоров’я реплікації?

Вік найновішого відновлюваного снапшоту на приймачі, по кожному критичному датасету. Не «успіх job-а», не пропускна здатність.
Вік снапшоту прямо відображає RPO.

2) Чи достатньо, що «снапшот існує на DR»?

Ні. Потрібно довести, що ви можете його використати: клонувати, змонтувати, завантажити ключі якщо зашифровано, і перевірити дані на рівні додатку.

3) Чи повинен датасет в DR монтуватись автоматично?

Зазвичай — ні. Поширена практика — canmount=noauto або mountpoint=none на DR, щоб уникнути випадкового використання.
Але необхідно задокументувати, як монтувати в DR, і протестувати це.

4) Чи можна безпечно реплікувати зашифровані датасети?

Так, але «безпечно» включає обробку ключів. Вирішіть, чи повинні ключі на DR бути завантажені за замовчуванням. Багато середовищ тримають ключі недоступними
і використовують break-glass процес. У будь-якому разі — тестуйте завантаження ключів і монтування.

5) Чому інкрементали іноді раптом збільшуються в розмірі?

Часті причини: велика churn (бази даних, зображення VM), помилки ретеншну (утримання старих снапшотів прикріплює змінені блоки),
або зміна робочого навантаження (наприклад, новий кеш-каталог). Використовуйте zfs send -nPv, щоб виміряти перед відправкою.

6) Що найчастіше ламає інкрементальну реплікацію?

Відсутні спільні снапшоти. Зазвичай спричинено обрізанням на приймачі, ручним видаленням снапшотів або невідповідністю імен/політик.
Захистіть вікно базових снапшотів.

7) Чи потрібні scrub-и на DR-пулі?

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

8) Як зрозуміти, що приймач — вузьке місце?

Перевірте IO пулу за допомогою zpool iostat -v під час receive і дивіться на затримки (через ваші метрики ОС).
Якщо мережа не повна, але записи повільні та диски завантажені — приймач обмежує.

9) Чи можна стискати send-стрім?

Потоки ZFS вже відображають стиснення датасету; додаткове зовнішнє стиснення рідко допомагає і може навантажити CPU.
Вимірюйте. Якщо CPU завантажений на відправнику/приймачі, ви не встигнете за RPO навіть на широкому лінку.

10) Чи варто реплікувати властивості?

Реплікуйте те, що важливо для коректності і продуктивності. Потім перевіряйте це.
Якщо ви навмисно відрізняєте DR (наприклад, canmount), фіксуйте цю відмінність явно, щоб вона не дрейфувала випадково.

Наступні кроки, які можна виконати цього тижня

  1. Реалізуйте перевірку RPO по датасету. Напишіть скрипт, якщо потрібно: порівнюйте час створення найновішого снапшоту на відправнику і приймачі.
    Сповіщайте, коли він перевищує політику.
  2. Проведіть одну вправу відновлення. Виберіть датасет, клонувати найновіший снапшот на DR, змонтуйте і перевірте на рівні додатку.
    Заміряйте час. Запишіть кожен крок, який довелося «пам’ятати».
  3. Аудитуйте дрейф охвату. Рекурсивно перелічіть датасети на відправнику і підтвердіть, що вони існують на приймачі.
    Якщо знайдете відсутні дочірні — поводьтеся з цим як з реальним інцидентом.
  4. Зробіть resume tokens пріоритетними. Якщо у вас ненадійні лінки, ігнорувати токени — значить обирати страждання.
    Сповіщайте про довгоживучі токени і побудуйте безпечний workflow для resume.
  5. Узгодьте ретеншн. Переконайтеся, що очищення снапшотів на приймачі не може видалити снапшоти, потрібні як бази інкременталів.
    Використовуйте holds там, де потрібно, і зробіть «тихі full send-и» соціально неприйнятними.
  6. Визначте політику шифрування в DR. Хто може завантажувати ключі? Як? Під яким дозволом? Попрактикуйте це.

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

← Попередня
Встановлення Linux Mint 22.3: перетворіть старий Windows ПК на ракету
Наступна →
Пакети Linux: безпечна стратегія оновлень, яка не ламає продакшн

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