Перейти до вмісту

Резервна копія

копія даних та її створення на випадок втрати

Що це таке

Резервна копія — це те, з чого відновлюють дані, коли оригінал видалено, пошкоджено або втрачено разом із машиною, на якій він зберігався, тож вона мусить лежати там, куди ці події не дістануть. Глосарій NIST визначає її як копію файлів і програм, зроблену для полегшення відновлення. У розмовній мові вживають слово бекап, а саму дію називають резервним копіюванням: нічне завдання виконує резервне копіювання бази даних і залишає по собі резервну копію.

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

Бази даних роблять це конкретним. Документація PostgreSQL описує три принципово різні підходи. SQL-дамп, створений через pg_dump, записує команди, які відтворюють базу, як узгоджений знімок того моменту, коли дамп почався. Резервна копія на рівні файлової системи копіює сам каталог даних. Безперервне архівування поєднує таку базову копію з журналом попереднього запису (write-ahead log, WAL), який сервер створює після неї, і відтворення цього журналу дає змогу відновити базу на будь-який момент після базової копії. Цю можливість називають відновленням на момент часу, point-in-time recovery.

Чому це важливо

Два числа перетворюють загальне бажання вберегти дані на проєкт. NIST визначає цільову точку відновлення, RPO, як момент часу, до якого дані мають бути відновлені після збою: на практиці це те, скільки останньої роботи бізнес може дозволити собі втратити. Цільовий час відновлення, RTO, — це те, як довго система може перебувати у відновленні, перш ніж збій зашкодить тому, заради чого існує організація.

Ці два числа тягнуть різні частини проєкту. RPO задає частота копій: нічний дамп може втратити день записів, а архівування WAL зменшує втрату до останніх миттєвостей журналу, які ще в дорозі до архіву. RTO задає тривалість відновлення. Документація PostgreSQL зазначає, що сервер відтворює кожен сегмент WAL від останньої базової копії, і це може тривати довго, якщо копія стара. Тож частота базових копій — таке саме рішення про RTO, як і про місце на диску.

Обидва числа — твердження про відновлення, і тому резервну копію оцінюють, відновлюючи її. Завдання, яке завершилося зі статусом нуль, показує лише, що десь записано байти. Чи відтворять вони робочу систему в межах RTO, показує відновлення за розкладом, поза продакшеном, з порівнянням того, що повернулося.

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

Як це виглядає на практиці

Усе, що зберігає одна компанія, стояло на одному хмарному екземплярі, і знімок провайдера був усією позицією відновлення: у тому самому обліковому записі, що й машина, без шифрування під власним контролем, і з нього ніколи не відновлювали. Йому на заміну прийшов таймер systemd, який робить дамп бази даних, надсилає зашифрований знімок restic з усуненням дублікатів до сховища в іншого провайдера через SFTP, підрізає старі знімки за політикою зберігання й запускає перевірку цілісності. Перемикач мертвої руки пінгується лише в разі успіху, тож тривогу здіймає саме тихий запуск. Окреме щомісячне навчання з відновлення витягує відомий файл із репозиторію та порівнює його, тож твердження, що компанія може втратити хост і повернути свої дані, спирається на відновлення минулого місяця, а не на резервне копіювання минулої ночі.

У більшому масштабі сто критичних резервних копій даних автоматизовано за допомогою Barman і Google Cloud для продукту, який живе своїми GIS-даними. Barman відповідав за PostgreSQL, Google Cloud тримав офсайт-копії, а Bash і Python оркестрували й перевіряли запуски. Перевірки цілісності підтверджували, що кожна копія справді придатна, а не просто наявна.

Ще в одному продукті позицію відновлення треба було визначити, а не припускати. Retention резервних копій живе в шаблоні Bicep поруч із базою даних, тож відновлення на момент часу є властивістю шаблону, а не налаштуванням, яке хтось колись клікнув у порталі, і середовище довкола теж описане кодом. Аудит записав прогалини: геонадлишковість вимкнено, а RTO запропоновано, а не виміряно, і навчання, яке його виміряє, описане й чекає на запуск.

Де виникають проблеми

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

Файлова копія робочої бази відновлюється як зламаний кластер. Якщо копіювати каталог даних PostgreSQL через tar, поки сервер працює, файли збираються з різних моментів, і документація вимагає зупинити сервер, щоб отримати придатну копію таким способом. Знімок файлової системи, зроблений в одну атомарну мить, спрацює, якщо містить WAL: сервер відтворить його під час запуску, як після аварії. Якщо дані й WAL лежать на різних файлових системах, одночасний знімок може виявитися неможливим. pg_dump або базова копія для безперервного архівування дає узгоджену копію, поки сервер працює далі.

Прогалина в архіві WAL обриває відновлення на момент часу саме на ній. Для відновлення потрібна неперервна послідовність заархівованих файлів WAL аж до початку базової копії. Якщо команда архівування раз у раз завершується помилкою, PostgreSQL повторює спроби, а WAL накопичується в pg_wal/, тож першим симптомом часто стає диск, що заповнюється. Документація радить налаштувати й перевірити архівування до першої базової копії та стежити за затримками.

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

Ключ губиться або надходить зміненим. Шифрування переносить увесь ризик на ключ, і документація restic каже прямо: втрата пароля означає, що дані безповоротно втрачено. Ключ має зберігатися там, де він переживе машину. У налаштуванні restic вище парольна фраза читається з файлу, а не з оточення, бо наглядач обробляє екранування у значеннях змінних оточення, і парольна фраза зі зворотною похилою рискою мовчки надійшла б іншою, ніж та, що створила репозиторій.

Політика зберігання видаляє саме ту копію, яка була потрібна. Пошкодження часто помічають через тижні, і політика, що тримає сім щоденних копій, на той час уже замінила кожну чисту копію пошкодженою. Багаторівнева політика зберігає довгий хвіст за невелику ціну, а --dry-run у restic показує, що політика видалила б, ще до того, як щось зникне:

restic forget --keep-daily 7 --keep-weekly 5 --keep-monthly 12 \
  --prune --dry-run

forget видаляє знімки, а prune — дані, на які посилалися лише вони, тож після prune старі копії зникають назавжди.

Перевірка цілісності проходить, а відновлення все одно ламається. Типово restic check перевіряє структуру репозиторію, не читаючи кожен pack-файл, бо для цього довелося б завантажити їх усі; --read-data читає все, а --read-data-subset=1/5 читає п’яту частину, тож п’ять запусків від 1/5 до 5/5 покривають усе. Повне читання доводить лише, що збережені байти цілі. Чи відтворять вони робочу базу з правильними ролями й налаштуваннями, покаже відновлення.

Що почитати далі

Словник