Резервне копіювання та відновлення БД реєстру

🌐 Цей документ доступний українською та англійською мовами. Використовуйте перемикач у правому верхньому куті, щоб змінити версію.

Postgres Operator від Crunchy Data (PGO), який використовується для управління БД реєстру,включає в себе pgBackRest - рішення для резервного копіювання та відновлення з відкритим кодом. PGO робить зручним виконання багатьох поширених дій, необхідних протягом життєвого циклу бази даних, зокрема:

  • Налаштування розкладів автоматичного резервного копіювання та політик збереження

  • Резервне копіювання даних у декілька місць

    • Підтримка резервного сховища в Kubernetes, AWS S3 (або S3-сумісних системах, таких як MinIO), Google Cloud Storage (GCS) і Azure Blob Storage

  • Одноразове створення резервних копій

  • Виконання «відновлення на певний момент часу» (PITR)

  • Клонування даних у новий екземпляр БД

1. Налаштування резервного копіювання

За замовчанням операційний та аналітичний кластери Postgres налаштовані таким чином, що вони постійно архівують журнал попереднього запису (WAL) та роблять повну резеврну копію раз на добу. Політикою збереження налаштовано зберігання однієї повної копії, таким чином після створення нової копії pgBackRest очистить попередню копію та пов’язані з нею файли WAL.

pgBackRest надає різні типи резервного копіювання, налаштувань політики збереження та розкладу резервного копіювання, які надають можливість налаштувати систему у відповідності з цільовими показниками точки відновлення (RPO), цільовим часом відновлення (RTO) та вимогами до викорастання простору.

1.1. Управління розкладом резервного копіювання

Розклад можна налаштувати для всіх трьох типів резервних копій:

  • full: резервна копія всього кластера Postgres. Це найбільший з усіх типів резервного копіювання.

  • differential: резервна копія всіх даних з часу останньої повної резервної копії.

  • incremental: резервна копія всіх даних з моменту останнього повного, диференціального або інкрементного резервного копіювання.

Розклади резервного копіювання зберігаються в розділі spec.backups.pgbackrest.repos.schedules. Кожне значення в цьому розділі приймає рядок у форматі cron, який визначає розклад резервного копіювання.

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

spec:
  backups:
    pgbackrest:
      repos:
      - name: repo1
        schedules:
          full: "0 1 * * 0"
          incremental: "0 1 * * 1-6"

Щоб керувати запланованим резервним копіюванням, PGO створить кілька Kubernetes CronJobs, які виконуватимуть резервне копіювання в указані періоди. Резервні копії використовуватимуть конфігурацію, яку ви вказали.

1.2. Управління політиками збереження резервних копій

PGO дозволяє встановити політики збереження резервних копій для повних і диференціальних резервних копій. Коли термін дії повної резервної копії закінчується, pgBackRest очистить усі пов’язані з нею резервні копії та файли WAL. Наприклад, якщо у вас є повна резервна копія з чотирма пов’язаними інкрементними резервними копіями, коли закінчується термін дії повної резервної копії, термін дії всіх її інкрементних резервних копій також закінчується.

Існує два типа політик repo1-retention-full-type які можна встановити:

  • count: на основі кількісті резервних копій, які ви хочете зберегти. Це значення за замовчанням.

  • time: на основі часу в днях. Повні резервні копії, старші за repo-retention-full, буде видалено зі сховища, якщо є принаймні одна резервна копія, яка дорівнює або перевищує параметр repo-retention-full

Наприклад, ми хочемо зберігати повні резервні копії протягом 14 днів. Найзручніший спосіб зробити це через розділ spec.backups.pgbackrest.global:

spec:
  backups:
    pgbackrest:
      global:
        repo1-retention-full: "14"
        repo1-retention-full-type: time

В такому випадку якщо ми маємо 2 резервні копії: одну 12-денну і другу 15-денну, жодна резервна копія не буде видалена тому що видалення 15-денної копії залишить лише 12-денну копію, що порушило б політику зберегання згідно з якою ми повинні мати принаймні одну резервну копію 14-денної давності, перш ніж видаляти старішу копію.

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

  • repo1-retention-archive - Кількість резервних копій для яких буде збережено WAL

  • repo1-retention-archive-type - Тип резервної копії для збереження WAL (incr,diff,full). Якщо встановлено значення full, pgBackRest зберігатиме WAL для кількості повних резервних копій, визначених repo-retention-archive. Якщо встановлено значення diff , pgBackRest зберігатиме архівні журнали для кількості повних і диференціальних резервних копій, визначених repo-retention-archive. Якщо встановлено значення incr, pgBackRest зберігатиме журнали архіву для кількості повних, диференціальних і інкрементних резервних копій, визначених repo-retention-archive.

1.3. Одноразове створення резервної копії

По-перше, вам потрібно налаштувати розділ spec.backups.pgbackrest.manual, щоб мати можливість зробити одноразову резервну копію. В ньому міститься інформація про тип резервної копії, яку ви хочете зробити, та будь-які інші параметри конфігурації pgBackRest.

Налаштуємо custom resource для одноразового створення повної резервної копії:

spec:
  backups:
    pgbackrest:
      manual:
        repoName: repo1
        options:
         - --type=full

Це ще не запускає резервне копіювання – ви повинні додати анотацію postgres-operator.crunchydata.com/pgbackrest-backup до свого custom resource. Найкращий спосіб налаштувати цю анотацію — за допомогою позначки часу, щоб ви знали, коли ви ініціалізували резервну копію.

Наприклад, для operational кластера ми можемо виконати таку команду, щоб запустити одноразове резервне копіювання:

kubectl annotate -n <registry-name> postgrescluster operational \
  postgres-operator.crunchydata.com/pgbackrest-backup="$(date)"
де <registry-name> — назва вашого реєстру/namespace.

PGO виявить цю анотацію та створить нове одноразове завдання резервного копіювання!

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

Щоб повторно запустити наведену вище команду, вам потрібно буде додати помітку --overwrite, щоб можна було оновити значення анотації, тобто.

kubectl annotate -n <registry-name> postgrescluster operational --overwrite \
  postgres-operator.crunchydata.com/pgbackrest-backup="$(date)"
де <registry-name> — назва вашого реєстру/namespace.

2. Відновлення

2.1. Відновлення на момент часу чи на конкретну резервну копію

Щоб відновити стан БД на потрібну дату і час, найперше, потрібно у секцію spec.backups.pgbackrest додати наступне:

spec:
  backups:
    pgbackrest:
      restore:
        enabled: true
        repoName: repo1
        options:
        - --type=time
        - --target="2022-06-09 14:15:11"

де --target цільовий час відновлення PITR. Прикладом часу відновлення є 2022-06-09 14:15:11.

Час відновлення вказується за UTC.

Щоб відновити базу на конкретну резервну копію, в секцію spec.backups.pgbackrest треба додати наступне:

spec:
  backups:
    pgbackrest:
      restore:
        enabled: true
        repoName: repo1
        options:
        - --type=immediate
        - --set=20220602-073427F_20220602-073507I

де --set назва цільової резервної копії. Список доступних резервних копій можно переглянути в бакеті s3 резервного сховища, або виконавши команду pgbackrest info --stanza=db в консолі поду БД.

Усі дані, створені після цільової дати відновлення (--target="2022-06-09 14:15:11") і до моменту початку процесу відновлення, будуть втрачені. Тому обов’язково потрібно врахувати це перед початком відновлення.

Щоб ініціювати відновлення, ви повинні додати анотацію postgres-operator.crunchydata.com/pgbackrest-restore наступним чином:

kubectl annotate -n <registry-name> postgrescluster operational --overwrite \
  postgres-operator.crunchydata.com/pgbackrest-restore="$(date)"
де <registry-name> — назва вашого реєстру/namespace.

Після завершення відновлення додане налаштування можна вимкнути:

spec:
  backups:
    pgbackrest:
      restore:
        enabled: false

Всі ці операції потрібно провести як на операційній, так і на аналітичній базі даних.

Для відновлення відповідності даних між операційною та аналітичною БД виконайте Узгодження данних на аналітичному кластері

2.2. Клонування з резервної копії

Для клонування БД з резервної копії треба додати в маніфест, який створює новий экземпляр БД, секцію spec.dataSource. Для відновлення на момент часу секція буде виглядати подібно до:

spec:
  dataSource:
    pgbackrest:
      stanza: db
      configuration:
      - secret:
          name: s3-conf
      global:
        repo1-path: "/postgres-backup/source_system/operational"
        repo1-s3-uri-style: path
        repo1-storage-verify-tls: n
        repo1-storage-port: "9000"
      options:
      - --type=time
      - --target="2022-06-09 14:15:11-04"
      repo:
        name: repo1
        s3:
          bucket: "bucketName"
          endpoint: "endpoint"
          region: "us-east-1"

Щоб відновити базу на конкретний бекап в секції spec.dataSource.pgbackrest.options треба змінити тип відновлення та задати ім’я резервної копії:

      options:
      - --type=immediate
      - --set=20220602-073427F_20220602-073507I

Всі ці операції потрібно провести як на операційній так і на аналітичній базі данних.

Для відновлення відповідності данних між операційною та аналітичною БД виконайте Узгодження данних на аналітичному кластері

2.3. Узгодження данних на аналітичному кластері

Оскільки операційна та аналітична баз реплікуються у асинхронному режимі, їх резервні копії не синхронізовані. Тому навіть при відновленні на той самий момент часу не може бути гарантована узгодженість данних між цими базами. Щоб привести відновлені бази в узгоджений стан потрібно виконати наступні кроки на базі registry аналітичного экземпляра:

  • Зупинити підписку: ALTER SUBSCRIPTION operational_sub DISABLE;

  • Очистити всі таблиці, які входять до підписки: SELECT 'TRUNCATE' ||' '||srrelid::regclass ||' '||'CASCADE;' FROM pg_subscription_rel \gexec

  • Видалити підписку: DROP SUBSCRIPTION operational_sub;

  • Створити підписку: create subscription operational_sub connection 'host=OperationalHost user=postgres dbname=registry password=XXXXXX' PUBLICATION analytical_pub WITH(create_slot=false,slot_name=operational_sub);

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

3. Безперервне відновлення на Standby-кластері

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

3.1. Створення Standby-кластера

Репозиторій резервних копій основного кластера має бути доступний для standby кластера. При створенні standby кластера необхідно додати в маніфест standby.enabled встановлений у true та параметри s3 репозиторія резервних копій основного кластера:

spec:
  backups:
    pgbackrest:
      image: registry.developers.crunchydata.com/crunchydata/crunchy-pgbackrest:ubi8-2.40-1
      repos:
      - name: repo1
        s3:
          bucket: "bucket"
          endpoint: "primary.endpoint"
          region: "ca-central-1"
  standby:
    enabled: true
    repoName: repo1

3.2. Підвищення (promote) Standby-кластера

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

Коли основний кластер стане неактивним, ми можемо підвищити standby кластер, видаливши або вимкнувши його розділ spec.standby:

spec:
  standby:
    enabled: false

Ця зміна запускає підвищення Standby кластера до основного, і кластер починає приймати записи.