Індекс журналуDockup / польова нотатка
Note / database-backups-you-have-restored

Резервна копія, яку ви ніколи не відновлювали, — не резервна копія

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

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

Тестування відновлення резервної копії бази даних — це не best practice у тому сенсі, у якому більшість best practices є необов’язковими. Резервна копія — це твердження, і доки ви її не відновили, це лише неперевірене твердження.

Ось як вони виходять з ладу і що насправді має перевіряти валідація.

Чотири способи, у які резервна копія непомітно стає марною

1. Вона порожня, і ніхто цього не помітив

pg_dump, який завершується помилкою посеред виконання, усе одно може створити файл. Дамп, запущений для бази даних із неправильним іменем, створює коректний, дійсний порожній файл. Для всього, що перевіряє ненульовий код завершення або наявність файлу, обидва випадки виглядають як успішні.

Найдешевша перевірка у світі: подивіться на розмір і порівняйте його із вчорашнім. Резервна копія розміром 400 байт, якщо вчорашня мала розмір 40 МБ, уже все вам сказала. А резервна копія розміром 400 байт упродовж шести місяців повідомляла про проблему весь цей час.

2. Вона містить дані, але не містить усього, що їх оточує

pg_dump однієї бази даних не містить ролей і не містить інших баз даних. Відновіть її на новому сервері — таблиці з’являться, а кожен GRANT посилатиметься на роль, якої не існує. Ваш застосунок підключиться, але отримає permission denied для всіх операцій.

З розширеннями та сама історія. Якщо ваша схема залежить від pgcrypto або uuid-ossp, а на цільовому сервері їх немає, відновлення завершиться помилкою посеред процесу, і у вас залишаться лише деякі таблиці.

3. Для потрібного вам відновлення було вибрано неправильні прапорці

pg_dump створює різні результати залежно від формату, і зазвичай помилку виявляють під тиском:

  • Plain SQL відновлюється за допомогою psql і є зручним для читання людиною. Вибіркове відновлення неможливе, а для великих баз даних цей формат повільний.
  • Custom format (-Fc) відновлюється за допомогою pg_restore, підтримує parallelism і вибіркове відновлення та є потрібним варіантом для всього, що має значний розмір.

Зберігати резервну копію в plain format лише тому, що так було в tutorial, а під час інциденту виявити, що ви не можете відновити одну таблицю, — це дуже конкретний і цілком запобіжний різновид невдалого дня.

4. Ви не можете її розшифрувати

Якщо резервні копії зашифровані — а вони мають бути зашифровані, — ключ є частиною резервної копії. Ключ, що зберігається лише на втраченій машині або лише в environment variable вимкненого сервісу, — це ключа у вас немає саме тоді, коли він потрібен.

Як виглядає справжня перевірка

Тест полягає не в тому, «чи існує файл». Потрібно відновити його в іншому місці й поставити йому запитання.

# 1. Restore into a scratch database, not the live one
createdb verify_$(date +%Y%m%d)
pg_restore -d verify_$(date +%Y%m%d) --no-owner --no-privileges latest.dump

# 2. Ask it something only real data can answer
psql -d verify_$(date +%Y%m%d) -c "
  select
    (select count(*) from users)            as users,
    (select count(*) from orders)           as orders,
    (select max(created_at) from orders)    as newest_order;
"

# 3. Drop it
dropdb verify_$(date +%Y%m%d)

Крок 2 — це і є вся суть. Відновлення, яке завершилося без помилки, усе одно нічого не говорить про те, чи є в базі дані. Про це свідчать кількість рядків і перевірка актуальності.

Варто перевіряти три речі:

  • Кількість рядків має бути того самого порядку величини. Не обов’язково точною — дані змінюються, — але таблиця, у якій було 200 000 рядків, а тепер залишилося 12, свідчить про збій.
  • Найновіший запис має бути свіжим. Якщо найновіше замовлення у вашій «нічній» резервній копії датоване березнем, завдання резервного копіювання зупинилося в березні.
  • Застосунок справді може підключитися. Спрямуйте staging instance на відновлену базу даних і завантажте одну сторінку.

Робіть це за розкладом, а не час від часу

Реалістична періодичність — щомісяця, автоматично, із результатом у місці, де ви його помітите. Нагадування в календарі «перевірити резервні копії» — це нагадування, яке ви просто відкладатимете.

Щоб цей процес справді працював, потрібно зробити збій гучним: якщо verification query повертає менше рядків, ніж визначено threshold, це має надіслати page відповідальній людині так само, як це зробила б production-помилка. Система резервного копіювання, яка мовчки виходить з ладу, нічим не відрізняється від відсутності системи резервного копіювання — аж до моменту, коли вона знадобиться.

Як Dockup працює з цим

Три рішення, кожне з яких спрямоване на конкретний описаний вище збій.

Резервні копії зберігаються в іншому місці. Резервна копія на тому самому диску, що й база даних, — не резервна копія, а лише копія, яка зникне разом із диском. Dockup безпосередньо передає резервні копії баз даних в object storage у міру їх створення, тому файл ніколи не залежить від хоста, на якому його створили.

Вони зашифровані, а ключ не зберігається на машині. Резервні копії шифруються за допомогою AES-256-GCM у процесі передавання. Для відновлення важливо те, що ключ зберігається на платформі, а не в environment сервісу, резервну копію якого створюють.

Резервна копія, під час створення якої нічого не отримано, не записується як резервна копія. Це безпосередньо усуває проблему порожнього файлу: якщо dump завершується з ненульовим кодом або створює нуль байтів, upload видаляється, а резервна копія записується як невдала. У вас не залишиться списку зелених записів, серед яких один є файлом розміром 400 байт.

dockup db backup my-project/main-db --json     # take one now
dockup db backups my-project/main-db --json    # list them with sizes

Розміри в цьому списку — найдешевша перевірка стану, яка у вас є. Слідкуйте за їхньою динамікою.

Незручне запитання

Якби ваша production-база даних була знищена протягом наступних десяти хвилин, скільки часу знадобилося б, щоб відновити її, і скільки даних ви б втратили?

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

Поширені запитання

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

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

Чи потрібно шифрувати резервні копії? Так, а ключ має зберігатися в місці, яке переживе втрату машини. Зашифрована резервна копія, ключ від якої зберігався на втраченому сервері, непридатна для відновлення.

Чи те саме snapshot, що й резервна копія? Ні. Volume snapshot фіксує диск, зокрема стан бази даних у конкретний момент. Logical dump за своєю побудовою є узгодженим. Більшості команд потрібні обидва варіанти, оскільки вони захищають від різних типів збоїв.