Workstation Logo
Продукты
AI LabsАгенты OpenAIАгенты ClaudeGrok BotWorkstation CRM (WSL CRM)МаркетингВсе продукты
Решения ИИ
Рабочие станции ИИAI SME PackagesЧастный ИИКластеры GPUПограничный ИИЛаборатория корпоративного ИИИИ по отраслям
Услуги
Platform ModernisationDigital EngineeringData Foundations & AIAutonomous OperationsИИ-консалтингАвтоматизация DevOpsКибербезопасностьРазработка ПОСоздание агентовНастройка MLOps
О нас
ПартнёрыИстории клиентов
Статьи
Документация
WSL ProxyRing PromoterWSL VaultJobshoutSysOps 24/7
Блог
Связаться с намиLogin
Workstation

AI-рабочие станции, мультиагентное AI-ПО, GPU-инфраструктура и решения на базе интеллектуальных агентов для современного бизнеса.

Связаться с нами

AI-решения

Рабочие станции ИИAI SME PackagesЧастный ИИКластеры GPUПограничный ИИЛаборатория корпоративного ИИИИ по отраслям

Продукты

Все продуктыWSL CRM и ERPМаркетингАгенты OpenAIWSL ProxyRing PromoterWSL VaultJobshoutSysOps 24/7

Компания

О насПочему WorkstationПартнёрыИстории клиентовЦеныКонтакты

Ресурсы

СтатьиДокументацияБлогПоискКарта сайта
Офис в Великобритании
77-79 Marlowes, Hemel Hempstead HP1 1LFКак добраться: съезд 20 с трассы M25, Внешний ЛондонРег. номер компании: 11641870Пн - Пт: 9:00 - 18:00 GMT
+44 7515 356 146
Офис в Бельгии
Workstation SRL, Rue Vanderkindere 34, 1180 Uccle, BrusselsBE 0751.518.683Пн - Пт: 9:00 - 18:00 CET
+32 492 45 67 46
Офис в Индии
#159 Sector 9, Pocket 1, DDA Flats, 110077 Dwarka, New Delhi
+91 98881 98841

© 2026 Workstation AI. Все права защищены.

КонфиденциальностьФайлы cookieУсловия использованияКарта сайта

Loading blog...

Home / Blog
DatabaseDevOpsKubernetesBackend

Стратегии резервного копирования производственных баз данных, которые действительно работают: MySQL и PostgreSQL

Проверенные стратегии резервного копирования и восстановления для MySQL и PostgreSQL в производстве

Balinder Walia12 апреля 2026 г.31 min read

Потеря производственных данных — это тот инцидент, который заканчивает карьеру, закрывает компании и попадает на первую полосу Hacker News по совершенно неправильным причинам. Тем не менее, большинство команд относятся к резервному копированию баз данных как к второстепенной задаче — задаче cron, которую кто-то настроил два года назад, и с тех пор никто не проверял. В этой статье излагаются проверенные в боевых условиях стратегии резервного копирования для MySQL и PostgreSQL, которые доказали свою эффективность в производственных средах, начиная от кластеров k3s с одним узлом и заканчивая облачными развертываниями в нескольких регионах, обрабатывающими миллионы транзакций ежедневно.

Мы охватим весь спектр: логические и физические методы резервного копирования, восстановление на определенный момент времени, автоматическое планирование, целевые объекты облачного хранилища, шифрование, проверку, собственные подходы Kubernetes и планирование аварийного восстановления, которое связывает все это воедино. Каждая рекомендация сопровождается конкретной конфигурацией и кодом, который вы можете адаптировать к своей среде.

Общие сведения о типах резервного копирования

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

Полная резервная копиязахватывает всю базу данных в один момент времени. Его проще всего рассуждать и быстрее всего восстанавливать, но он также самый дорогой в хранении и самый медленный в создании. Инкрементное резервное копированиесохраняет только те данные, которые изменились с момента последнего резервного копирования любого типа. Его можно быстро создать и компактно хранить, но для восстановления требуется воспроизведение всей цепочки: последняя полная резервная копия плюс каждая последующая инкрементальная. Дифференциальное резервное копированиефиксирует все изменения, произошедшие с момента последнего полного резервного копирования. Он занимает золотую середину — больше, чем инкрементный, но его проще восстановить, поскольку вам нужны только последний полный плюс последний дифференциал. Наконец, функция непрерывного архивирования(архивирование WAL в PostgreSQL, потоковая передача двоичного журнала в MySQL) фиксирует каждую отдельную транзакцию по мере ее возникновения, обеспечивая возможность восстановления на определенный момент времени между резервными копиями.

Обзор стратегии резервного копирования: полное, инкрементальное, дифференциальное и непрерывноеДень 0День 1День 2День 3День 4День 5ПолныйИнкр.Диф.WAL/БинлогПОЛНЫЙ (100%)ПОЛНЫЙ (100%)+5%+3%+4%+2%+5%+8%+12%+14%Непрерывный поток WAL/двоичного журнала (каждая транзакция)Цель восстановленияПолное резервное копированиеИнкрементальныйДифференциалПоток WAL/BinlogТочка восстановления

Оптимальной стратегией для большинства производственных систем является комбинация: еженедельное полное резервное копирование, ежедневное инкрементное или дифференциальное резервное копирование и непрерывное архивирование WAL/binlog. Это дает вам как быстрое восстановление из последних полных резервных копий, так и возможность восстановления в любой момент времени, когда вам это нужно.

Методы резервного копирования MySQL

MySQL предлагает несколько инструментов резервного копирования, каждый из которых подходит для разных размеров баз данных и требований к восстановлению. Правильный выбор зависит от объема ваших данных, приемлемого окна резервного копирования и целевых показателей RTO/RPO.

mysqldump — универсальное логическое резервное копирование

mysqldumpсоздает операторы SQL, воссоздающие схему и данные. Он работает на любой версии MySQL и механизме хранения данных, что делает его универсальным запасным вариантом. Однако он блокирует таблицы во время дампа (если только не используется--single-transactionс InnoDB), а скорость восстановления значительно снижается для баз данных размером более 50–100 ГБ, поскольку он воспроизводит отдельные инструкции INSERT.

# Full logical backup with consistent snapshot for InnoDB
mysqldump --single-transaction --routines --triggers --events \
  --set-gtid-purged=ON --all-databases \
  | gzip > /backups/mysql-full-$(date +%Y%m%d-%H%M%S).sql.gz

# Single database backup with compression
mysqldump --single-transaction --routines --triggers \
  --databases production_db \
  | pigz -p4 > /backups/production_db-$(date +%Y%m%d).sql.gz

# Schema-only backup for migration planning
mysqldump --no-data --routines --triggers --events \
  --all-databases > /backups/schema-only-$(date +%Y%m%d).sql

mysqlpump — параллельное логическое резервное копирование

mysqlpump— усовершенствованная версияmysqldumpза счет параллельного дампа таблиц и встроенной функции сжатия. Это может значительно сократить время резервного копирования баз данных с множеством независимых таблиц.

# Parallel logical backup with 4 threads and zstd compression
mysqlpump --default-parallelism=4 --compress-output=ZSTD \
  --include-databases=production_db,analytics_db \
  --set-gtid-purged=ON \
  > /backups/mysql-pump-$(date +%Y%m%d).sql.zst

Percona XtraBackup — физическое резервное копирование для InnoDB

Для баз данных размером более 50 ГБ логическое резервное копирование становится нецелесообразным — как окно резервного копирования, так и время восстановления растут линейно с размером данных. Percona XtraBackup создает копии файлов данных InnoDB на физическом уровне без блокировки базы данных, что делает ее подходящей для развертываний объемом несколько терабайт.

# Full physical backup with streaming to compressed archive
xtrabackup --backup --target-dir=/backups/full-$(date +%Y%m%d) \
  --user=backup_user --password=secure_pass \
  --parallel=4 --compress --compress-threads=4

# Incremental backup based on last full
xtrabackup --backup --target-dir=/backups/incr-$(date +%Y%m%d) \
  --incremental-basedir=/backups/full-20260412 \
  --user=backup_user --password=secure_pass \
  --parallel=4

# Stream full backup directly to S3 via xbstream
xtrabackup --backup --stream=xbstream --compress \
  --user=backup_user --password=secure_pass | \
  aws s3 cp - s3://db-backups/mysql/full-$(date +%Y%m%d).xbstream

# Prepare for restore (apply redo log)
xtrabackup --prepare --target-dir=/backups/full-20260412

# Prepare incremental on top of full
xtrabackup --prepare --apply-log-only --target-dir=/backups/full-20260412
xtrabackup --prepare --target-dir=/backups/full-20260412 \
  --incremental-dir=/backups/incr-20260412

# Restore
systemctl stop mysqld
xtrabackup --copy-back --target-dir=/backups/full-20260412
chown -R mysql:mysql /var/lib/mysql
systemctl start mysqld

Бинарный журнал MySQL — восстановление на определенный момент времени

В двоичных журналах

MySQL фиксируются все операторы, изменяющие данные, или изменения строк. В сочетании с полным или физическим резервным копированием они позволяют выполнить восстановление на любой момент времени после создания резервной копии.

# Enable binary logging in my.cnf
[mysqld]
server-id = 1
log-bin = /var/log/mysql/mysql-bin
binlog_format = ROW
binlog_expire_logs_seconds = 604800   # 7 days
sync_binlog = 1
gtid_mode = ON
enforce_gtid_consistency = ON

# Flush and archive binary logs
mysqladmin flush-logs
mysqlbinlog --read-from-remote-server --host=db-primary \
  --raw --stop-never --result-file=/backup/binlogs/ \
  mysql-bin.000042

# Point-in-time recovery: replay binlog up to specific timestamp
mysqlbinlog --stop-datetime="2026-04-12 14:30:00" \
  /backup/binlogs/mysql-bin.000042 \
  /backup/binlogs/mysql-bin.000043 | mysql -u root

Методы резервного копирования PostgreSQL

Экосистема резервного копирования PostgreSQL, возможно, богаче, чем у MySQL, благодаря инструментам сторонних разработчиков и зрелому набору общественных решений, специально созданных для крупномасштабных производственных сред.

pg_dump и pg_dumpall — логическое резервное копирование

Как иmysqldump,pg_dumpсоздает логические резервные копии. Пользовательский формат (-Fc) является рекомендуемым по умолчанию, поскольку он поддерживает параллельное восстановление, выборочное восстановление таблиц и встроенное сжатие.

# Custom format with parallel dump (4 worker jobs)
pg_dump -Fc -j4 -f /backups/production-$(date +%Y%m%d).dump production_db

# Directory format for maximum parallelism on large databases
pg_dump -Fd -j8 -f /backups/production-$(date +%Y%m%d)/ production_db

# All databases including globals (roles, tablespaces)
pg_dumpall > /backups/pg-all-$(date +%Y%m%d).sql

# Parallel restore from custom format
pg_restore -j4 -d production_db_restored /backups/production-20260412.dump

# Selective restore: single table
pg_restore -j4 -d production_db -t orders /backups/production-20260412.dump

pg_basebackup — Фонд физического резервного копирования

pg_basebackupсоздает физическую копию всего каталога данных PostgreSQL. Это основа как для автономного восстановления, так и для настройки потоковой репликации. В сочетании с архивированием WAL это обеспечивает восстановление на определенный момент времени.

# Physical backup with WAL files included
pg_basebackup -D /backups/base-$(date +%Y%m%d) \
  -Ft -z -Xs -P -c fast \
  -U replication_user -h db-primary

# Stream backup directly to a tar archive with checksums
pg_basebackup -D - -Ft -Xs -c fast \
  -U replication_user -h db-primary | \
  gzip > /backups/pg-base-$(date +%Y%m%d).tar.gz

pgBackRest — управление резервным копированием корпоративного уровня

pgBackRest — это золотой стандарт управления резервным копированием PostgreSQL. Он поддерживает полное, инкрементное и дифференциальное резервное копирование, параллельное резервное копирование и восстановление, шифрование, целевые объекты с несколькими репозиториями (локальный диск, S3, GCS, Azure Blob) и автоматическое архивирование WAL — и все это посредством единой связной конфигурации.

# /etc/pgbackrest/pgbackrest.conf
[global]
repo1-type=s3
repo1-s3-bucket=pg-backups-production
repo1-s3-endpoint=s3.eu-west-1.amazonaws.com
repo1-s3-region=eu-west-1
repo1-s3-key=AKIAIOSFODNN7EXAMPLE
repo1-s3-key-secret=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
repo1-path=/pgbackrest
repo1-retention-full=4
repo1-retention-diff=14
repo1-cipher-type=aes-256-cbc
repo1-cipher-pass=a_very_secure_encryption_passphrase

# Second repository for geographic redundancy
repo2-type=azure
repo2-azure-container=pg-backups-dr
repo2-azure-account=prodbackupstorage
repo2-azure-key=base64encodedkeyhere
repo2-path=/pgbackrest
repo2-retention-full=2

process-max=4
compress-type=zst
compress-level=6
log-level-console=info
log-level-file=detail
start-fast=y

[production]
pg1-path=/var/lib/postgresql/16/main
pg1-port=5432

# PostgreSQL WAL archive configuration (postgresql.conf)
# archive_mode = on
# archive_command = 'pgbackrest --stanza=production archive-push %p'

# Create the stanza
pgbackrest --stanza=production stanza-create

# Verify the stanza configuration
pgbackrest --stanza=production check

# Full backup
pgbackrest --stanza=production --type=full backup

# Differential backup
pgbackrest --stanza=production --type=diff backup

# Incremental backup
pgbackrest --stanza=production --type=incr backup

# List backups
pgbackrest --stanza=production info

WAL-G — облегченное архивирование WAL в облачное хранилище

WAL-G — это более простая альтернатива pgBackRest, которая фокусируется на потоковой передаче сегментов WAL и базовых резервных копий в облачное хранилище объектов. Он популярен в контейнерных средах, где вам нужен один двоичный файл с минимальной конфигурацией.

# Environment variables for WAL-G with S3
export WALG_S3_PREFIX=s3://pg-wal-archive/production
export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
export AWS_REGION=eu-west-1
export WALG_COMPRESSION_METHOD=lz4
export PGHOST=/var/run/postgresql

# Configure WAL archiving in postgresql.conf
# archive_mode = on
# archive_command = 'wal-g wal-push %p'
# restore_command = 'wal-g wal-fetch %f %p'

# Take a base backup
wal-g backup-push /var/lib/postgresql/16/main

# List backups
wal-g backup-list

# Restore from latest backup
wal-g backup-fetch /var/lib/postgresql/16/main LATEST

# Delete old backups (retain last 4)
wal-g delete retain FULL 4 --confirm

Barman — Централизованный сервер резервного копирования

Barman (Менеджер резервного копирования и восстановления) предназначен для сред, в которых выделенный сервер резервного копирования управляет резервными копиями для нескольких экземпляров PostgreSQL. Он поддерживает протоколы rsync/SSH и потоковой репликации для резервного транспорта.

# /etc/barman.d/production.conf
[production]
description = "Production PostgreSQL 16"
ssh_command = ssh postgres@db-primary
conninfo = host=db-primary user=barman dbname=postgres
streaming_conninfo = host=db-primary user=streaming_barman
backup_method = postgres
streaming_archiver = on
slot_name = barman
retention_policy = RECOVERY WINDOW OF 14 DAYS

# Create replication slot and start streaming
barman receive-wal --create-slot production
barman switch-wal --force --archive production

# Take a backup
barman backup production

# List backups
barman list-backup production

# Restore to point in time
barman recover --target-time "2026-04-12 14:30:00" \
  production 20260412T120000 /var/lib/postgresql/16/main

Восстановление на определенный момент времени (PITR)

Восстановление на определенный момент времени — самая важная возможность в вашем наборе инструментов резервного копирования. Он позволяет восстановить базу данных в то состояние, в котором она находилась в любой конкретный момент — не только во время создания резервных копий, но и в любую секунду между резервными копиями. Это критически важно для восстановления после случайного удаления данных, ошибок приложений, повреждающих данные, и инцидентов безопасности, когда вам необходимо определить точный момент компрометации.

Восстановление на определенный момент времени (PITR) Временная шкала00:00Солнце06:0012:0018:0000:00ПнПолное резервное копированиеpg_basebackup@ 00:00WAL/сегменты двоичного журнала (непрерывно)✖ОТКИДНОЙ СТОЛ@ 16:42:31Цель восстановления@ 16:42:301. Восстановите полную версию.2. Воспроизведите WAL для целевого.3. БД восстановлена!PITR = Восстановление последней полной резервной копии + Воспроизведение сегментов WAL/binlog за 1 секунду до катастрофыДетализация восстановления: по транзакциям (PostgreSQL WAL) или посекундно (binlog MySQL)

PITR для PostgreSQL

PostgreSQL PITR работает путем восстановления базовой резервной копии и воспроизведения сегментов WAL до целевой временной метки. При использовании pgBackRest весь процесс представляет собой одну команду.

# Restore to specific point in time with pgBackRest
pgbackrest --stanza=production \
  --type=time --target="2026-04-12 16:42:30" \
  --target-action=promote \
  restore

# Manual PITR using pg_basebackup + WAL archive
# 1. Stop PostgreSQL
systemctl stop postgresql

# 2. Clear the data directory and restore base backup
rm -rf /var/lib/postgresql/16/main/*
tar xzf /backups/pg-base-20260412.tar.gz -C /var/lib/postgresql/16/main/

# 3. Create recovery signal and configure restore
cat > /var/lib/postgresql/16/main/postgresql.auto.conf << 'CONF'
restore_command = 'cp /backup/wal_archive/%f %p'
recovery_target_time = '2026-04-12 16:42:30'
recovery_target_action = 'promote'
CONF
touch /var/lib/postgresql/16/main/recovery.signal

# 4. Start PostgreSQL — it will replay WAL and stop at target
systemctl start postgresql

PITR для MySQL

MySQL PITR сочетает в себе физическое восстановление XtraBackup и воспроизведение двоичного журнала.

# 1. Restore the XtraBackup
systemctl stop mysqld
rm -rf /var/lib/mysql/*
xtrabackup --prepare --target-dir=/backups/full-20260412
xtrabackup --copy-back --target-dir=/backups/full-20260412
chown -R mysql:mysql /var/lib/mysql
systemctl start mysqld

# 2. Identify the binlog position from XtraBackup metadata
cat /backups/full-20260412/xtrabackup_binlog_info
# Output: mysql-bin.000042  154  3E11FA47-1111-1111-1111-AAAAAAAAAAAA:1-1234

# 3. Replay binlogs up to target time
mysqlbinlog --start-position=154 \
  --stop-datetime="2026-04-12 16:42:30" \
  /backup/binlogs/mysql-bin.000042 \
  /backup/binlogs/mysql-bin.000043 | mysql -u root

Мультиоблачная архитектура резервного копирования

Стратегии производственного резервного копирования

должны учитывать сбои любого отдельного поставщика облачных услуг или региона. Хранение резервных копий исключительно в той же облачной учетной записи и регионе, что и ваша рабочая база данных, означает, что взлом одной учетной записи, проблема с выставлением счетов или региональный сбой могут привести к одновременному уничтожению как ваших данных, так и ваших резервных копий. Надежная архитектура отправляет резервные копии как минимум в два независимых хранилища с межрегиональной репликацией.

Архитектура мультиоблачного резервного копированияPostgreSQLПервичный + репликиMySQLПервичный + репликиУровень шифрованияAES-256-CBCTLS в путиSSE-S3 / SSE-KMSв состоянии покояШифрование на стороне клиентачерез pgBackRest/ WAL-GAWS S3eu-west-1 (основной)Жизненный цикл: IA → ЛедникAzure БлобЗападная Европа (основной)Политики неизменяемостиОблачное хранилище GoogleЕвропа-Запад1 (основной)Nearline → Холодная линияS3 МежрегиональныйСША-Восток-1 (ДР)Azure GRSСеверная Европа (ДР)Многорегиональный GCSЕС, многорегиональный (DR)Мониторинг резервного копирования и усиление; ОповещениеМетрики Prometheus • Панели мониторинга Grafana • Оповещения PagerDuty/Slack при сбое резервного копирования или пороге возрастаСплошные стрелки = резервный потокПунктирные стрелки = межрегиональная репликацияПунктирный прямоугольник = граница шифрованияКонфигурация облачного хранилища

с политиками жизненного цикла

# AWS S3 lifecycle policy (Terraform)
resource "aws_s3_bucket_lifecycle_configuration" "backup_lifecycle" {
  bucket = aws_s3_bucket.db_backups.id

  rule {
    id     = "backup-tiering"
    status = "Enabled"

    transition {
      days          = 30
      storage_class = "STANDARD_IA"
    }
    transition {
      days          = 90
      storage_class = "GLACIER"
    }
    transition {
      days          = 365
      storage_class = "DEEP_ARCHIVE"
    }
    expiration {
      days = 2555  # 7 years for compliance
    }
  }

  rule {
    id     = "wal-segments"
    status = "Enabled"
    filter {
      prefix = "wal-archive/"
    }
    expiration {
      days = 30
    }
  }
}

# Enable cross-region replication
resource "aws_s3_bucket_replication_configuration" "backup_replication" {
  bucket = aws_s3_bucket.db_backups.id
  role   = aws_iam_role.replication.arn

  rule {
    id     = "cross-region-dr"
    status = "Enabled"
    destination {
      bucket        = aws_s3_bucket.db_backups_dr.arn
      storage_class = "STANDARD_IA"
      encryption_configuration {
        replica_kms_key_id = aws_kms_key.dr_key.arn
      }
    }
    source_selection_criteria {
      sse_kms_encrypted_objects {
        status = "Enabled"
      }
    }
  }
}
# Azure Blob immutability policy (Azure CLI)
az storage container immutability-policy create \
  --account-name prodbackupstorage \
  --container-name pg-backups \
  --period 365 \
  --allow-protected-append-writes true

# GCS lifecycle with nearline transition
gsutil lifecycle set /dev/stdin gs://pg-backups-production << 'JSON'
{
  "rule": [
    {"action": {"type": "SetStorageClass", "storageClass": "NEARLINE"}, "condition": {"age": 30}},
    {"action": {"type": "SetStorageClass", "storageClass": "COLDLINE"}, "condition": {"age": 90}},
    {"action": {"type": "Delete"}, "condition": {"age": 2555}}
  ]
}
JSON

Шифрование и безопасность резервного копирования

Резервные копии

— ценная цель для злоумышленников. Украденная незашифрованная резервная копия дает злоумышленнику полную копию ваших производственных данных без необходимости взлома работающих систем. Каждая резервная копия, как в пути, так и в состоянии покоя, должна быть зашифрована.

Шифрование при передачеозначает использование TLS для всех соединений между сервером базы данных и местом назначения резервного копирования. И pgBackRest, и XtraBackup осуществляют потоковую передачу по зашифрованным каналам при настройке с помощью TLS. При отправке в S3, Azure Blob или GCS клиентские SDK по умолчанию используют HTTPS.

Шифрование неактивного состоянияимеет два уровня. Шифрование на стороне сервера (SSE) шифрует данные после их поступления в целевое хранилище — S3 SSE-KMS, шифрование службы хранения Azure или шифрование по умолчанию GCS. Шифрование на стороне клиента шифрует данные до того, как они покинут сервер базы данных, гарантируя, что облачный провайдер никогда не увидит данные в виде открытого текста. pgBackRest и WAL-G изначально поддерживают шифрование на стороне клиента.

# pgBackRest client-side encryption config
repo1-cipher-type=aes-256-cbc
repo1-cipher-pass=long_random_passphrase_stored_in_vault

# WAL-G client-side encryption
export WALG_LIBSODIUM_KEY=$(cat /etc/wal-g/encryption.key)
# Or GPG-based
export WALG_GPG_KEY_ID=backup@example.com

# MySQL XtraBackup with encryption
xtrabackup --backup --encrypt=AES256 \
  --encrypt-key-file=/etc/mysql/backup-encryption.key \
  --target-dir=/backups/full-encrypted-$(date +%Y%m%d)

Храните ключи шифрования отдельно от самих резервных копий. Рекомендуется использовать менеджер секретов, например HashiCorp Vault, AWS Secrets Manager или Azure Key Vault. Если вы храните ключ вместе с резервной копией, злоумышленник, получивший доступ к вашему хранилищу резервных копий, получит все необходимое.

Автоматическое планирование резервного копирования

Резервное копирование вручную — это не резервное копирование, а стремление. Расписания резервного копирования должны быть автоматизированы, контролироваться и предупреждать о сбоях.

Системный Cron для «голого железа» и виртуальных машин

# /etc/cron.d/database-backups

# PostgreSQL — pgBackRest
# Full backup every Sunday at 01:00
0 1 * * 0 postgres pgbackrest --stanza=production --type=full backup 2>&1 | logger -t pgbackrest-full

# Differential backup every day at 01:00 (except Sunday)
0 1 * * 1-6 postgres pgbackrest --stanza=production --type=diff backup 2>&1 | logger -t pgbackrest-diff

# MySQL — XtraBackup
# Full backup every Sunday at 02:00
0 2 * * 0 root /usr/local/bin/mysql-backup.sh full 2>&1 | logger -t xtrabackup-full

# Incremental backup every day at 02:00 (except Sunday)
0 2 * * 1-6 root /usr/local/bin/mysql-backup.sh incremental 2>&1 | logger -t xtrabackup-incr

# Backup verification — restore test every Wednesday at 04:00
0 4 * * 3 root /usr/local/bin/verify-backup.sh 2>&1 | logger -t backup-verify

Kubernetes Задания CronJobs

В средах Kubernetes задания CronJob заменяют системный cron. Они предлагают встроенную логику повторных попыток, управление параллелизмом, интеграцию с RBAC кластера и управление секретами.

apiVersion: batch/v1
kind: CronJob
metadata:
  name: pg-backup-full
  namespace: database
spec:
  schedule: "0 1 * * 0"  # Sunday 01:00 UTC
  concurrencyPolicy: Forbid
  successfulJobsHistoryLimit: 4
  failedJobsHistoryLimit: 3
  jobTemplate:
    spec:
      backoffLimit: 2
      activeDeadlineSeconds: 7200  # 2 hour timeout
      template:
        spec:
          serviceAccountName: db-backup
          restartPolicy: OnFailure
          containers:
            - name: pgbackrest
              image: pgbackrest/pgbackrest:2.50
              command:
                - /bin/bash
                - -c
                - |
                  pgbackrest --stanza=production --type=full backup
                  RESULT=$?
                  if [ $RESULT -eq 0 ]; then
                    curl -s -X POST "$SLACK_WEBHOOK" \
                      -d '{"text":"PostgreSQL full backup completed successfully"}'
                  else
                    curl -s -X POST "$SLACK_WEBHOOK" \
                      -d '{"text":"ALERT: PostgreSQL full backup FAILED"}'
                  fi
                  exit $RESULT
              envFrom:
                - secretRef:
                    name: pgbackrest-credentials
                - secretRef:
                    name: slack-webhook
              resources:
                requests:
                  memory: 512Mi
                  cpu: 500m
                limits:
                  memory: 2Gi
                  cpu: "2"
              volumeMounts:
                - name: pgbackrest-config
                  mountPath: /etc/pgbackrest
          volumes:
            - name: pgbackrest-config
              configMap:
                name: pgbackrest-conf
---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: pg-backup-diff
  namespace: database
spec:
  schedule: "0 1 * * 1-6"  # Mon-Sat 01:00 UTC
  concurrencyPolicy: Forbid
  successfulJobsHistoryLimit: 7
  failedJobsHistoryLimit: 3
  jobTemplate:
    spec:
      backoffLimit: 2
      activeDeadlineSeconds: 3600
      template:
        spec:
          serviceAccountName: db-backup
          restartPolicy: OnFailure
          containers:
            - name: pgbackrest
              image: pgbackrest/pgbackrest:2.50
              command:
                - /bin/bash
                - -c
                - |
                  pgbackrest --stanza=production --type=diff backup
              envFrom:
                - secretRef:
                    name: pgbackrest-credentials
              resources:
                requests:
                  memory: 256Mi
                  cpu: 250m
                limits:
                  memory: 1Gi
                  cpu: "1"
              volumeMounts:
                - name: pgbackrest-config
                  mountPath: /etc/pgbackrest
          volumes:
            - name: pgbackrest-config
              configMap:
                name: pgbackrest-conf
---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: mysql-backup-full
  namespace: database
spec:
  schedule: "0 2 * * 0"
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      backoffLimit: 2
      activeDeadlineSeconds: 7200
      template:
        spec:
          serviceAccountName: db-backup
          restartPolicy: OnFailure
          containers:
            - name: xtrabackup
              image: percona/percona-xtrabackup:8.0
              command:
                - /bin/bash
                - -c
                - |
                  xtrabackup --backup --stream=xbstream --compress \
                    --user=$MYSQL_BACKUP_USER \
                    --password=$MYSQL_BACKUP_PASS \
                    --host=mysql-primary.database.svc | \
                    aws s3 cp - s3://$S3_BUCKET/mysql/full-$(date +%Y%m%d).xbstream
              envFrom:
                - secretRef:
                    name: mysql-backup-credentials
                - secretRef:
                    name: aws-credentials
              resources:
                requests:
                  memory: 512Mi
                  cpu: 500m
                limits:
                  memory: 2Gi
                  cpu: "2"

Kubernetes-собственный подход к резервному копированию

Запуск баз данных в Kubernetes открывает новое измерение стратегии резервного копирования. Помимо резервного копирования базы данных на уровне приложения, вам необходимо рассмотреть резервное копирование на уровне кластера (etcd), снимки постоянных томов и резервные копии, управляемые оператором.

Резервный трубопровод KubernetesКластер Kubernetes (k3s / RKE2)Задание CronJobРасписание: 0 1 * * *Модуль резервного копированияpgBackRest /Контейнер XtraBackupМодуль PostgreSQLРепликаStatefulSet 0PVC: pg-данныеМодуль MySQLРепликаStatefulSet 0PVC: данные mysqlЛонгхорн CSIPV-снимки + репликиVolume Snapshot CRDВелероРезервное копирование на уровне кластераetcd + пространства имен + PVОбъектное хранилищеS3/GCS/Azure Blob/MinIOЗашифрованный & версияПоддержка многоуровневого жизненного циклаРезервные копии БД + WALВелероЦель Longhorn S3Prometheus + GrafanaПоказатели заданий резервного копирования и оповещенияЧастота успешных/неудачных заданий CronJobПуть восстановления1. Восстановление Velero (кластер)2. pgBackRest/XtraBackup (данные)3. Откат снимка LonghornПланировщикАгент резервного копированияPostgreSQLMySQLВелероЛонгхорнОбъектное хранилище

Velero для резервного копирования на уровне кластера

Velero выполняет резервное копирование ресурсов Kubernetes (развертываний, служб, карт конфигурации, секретов) и постоянных томов. Это не замена резервному копированию базы данных на уровне приложения — он создает отказоустойчивый снимок физических объектов, который может не быть транзакционно-согласованным для баз данных. Используйте Velero для восстановления кластера и инструменты уровня приложения (pgBackRest, XtraBackup) для восстановления базы данных.

# Install Velero with S3 backend
velero install \
  --provider aws \
  --bucket velero-backups \
  --secret-file ./credentials-velero \
  --backup-location-config region=eu-west-1 \
  --snapshot-location-config region=eu-west-1 \
  --use-volume-snapshots=true \
  --plugins velero/velero-plugin-for-aws:v1.9.0

# Create a scheduled backup of the database namespace
velero schedule create db-namespace-backup \
  --schedule="0 3 * * *" \
  --include-namespaces database \
  --ttl 720h \
  --storage-location default \
  --volume-snapshot-locations default

# On-demand backup before maintenance
velero backup create pre-maintenance-$(date +%Y%m%d) \
  --include-namespaces database,monitoring \
  --wait

# Restore a namespace from backup
velero restore create --from-backup pre-maintenance-20260412 \
  --include-namespaces database
Снимки

Longhorn на k3s

В развертываниях

k3s обычно используется Longhorn в качестве поставщика систем хранения данных CSI. Longhorn предоставляет снимки уровня тома и возможность репликации снимков в S3-совместимое объектное хранилище. Для баз данных комбинируйте снимки Longhorn с резервными копиями на уровне приложений для обеспечения глубокой защиты.

# Longhorn recurring snapshot job via CRD
apiVersion: longhorn.io/v1beta2
kind: RecurringJob
metadata:
  name: pg-data-snapshot
  namespace: longhorn-system
spec:
  cron: "0 */4 * * *"  # every 4 hours
  task: snapshot
  retain: 6
  concurrency: 1
  groups:
    - pg-data
  labels:
    app: postgresql
---
# Longhorn recurring backup to S3
apiVersion: longhorn.io/v1beta2
kind: RecurringJob
metadata:
  name: pg-data-s3-backup
  namespace: longhorn-system
spec:
  cron: "0 2 * * *"  # daily at 02:00
  task: backup
  retain: 14
  concurrency: 1
  groups:
    - pg-data
  labels:
    app: postgresql
---
# VolumeSnapshot using Longhorn CSI
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: pg-data-snap-$(date +%Y%m%d)
  namespace: database
spec:
  volumeSnapshotClassName: longhorn-snapshot-vsc
  source:
    persistentVolumeClaimName: pg-data-postgresql-0

Резервное копирование, управляемое оператором

Операторы баз данных, такие как CloudNativePG (для PostgreSQL) и Percona Оператор (для MySQL), интегрируют управление резервным копированием непосредственно в жизненный цикл базы данных. Оператор автоматически управляет планированием, архивированием и хранением WAL с помощью пользовательских ресурсов.

# CloudNativePG cluster with integrated backup
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: production-pg
  namespace: database
spec:
  instances: 3
  storage:
    size: 100Gi
    storageClass: longhorn
  backup:
    barmanObjectStore:
      destinationPath: s3://pg-backups/cnpg/
      endpointURL: https://s3.eu-west-1.amazonaws.com
      s3Credentials:
        accessKeyId:
          name: aws-creds
          key: ACCESS_KEY_ID
        secretAccessKey:
          name: aws-creds
          key: SECRET_ACCESS_KEY
      wal:
        compression: gzip
        maxParallel: 4
      data:
        compression: gzip
    retentionPolicy: "30d"
---
apiVersion: postgresql.cnpg.io/v1
kind: ScheduledBackup
metadata:
  name: production-pg-weekly
  namespace: database
spec:
  schedule: "0 1 * * 0"
  backupOwnerReference: self
  cluster:
    name: production-pg

Облачные стратегии для конкретного поставщика

AWS — RDS и Аврора

AWS RDS обеспечивает автоматические ежедневные снимки с настраиваемым сроком хранения (до 35 дней) и непрерывное резервное копирование посредством архивирования журнала транзакций для восстановления на определенный момент времени. Aurora добавляет Backtrack, который может перематывать кластер в любую точку в окне возврата без необходимости восстановления — он просто меняет внутреннее состояние базы данных.

# Enable automated backups with maximum retention (Terraform)
resource "aws_db_instance" "production" {
  identifier             = "production-pg"
  engine                 = "postgres"
  engine_version         = "16.2"
  instance_class         = "db.r6g.xlarge"
  allocated_storage      = 500
  backup_retention_period = 35  # maximum
  backup_window          = "03:00-04:00"
  copy_tags_to_snapshot  = true
  deletion_protection    = true
  storage_encrypted      = true
  kms_key_id             = aws_kms_key.rds.arn

  # Enable PITR
  enabled_cloudwatch_logs_exports = ["postgresql", "upgrade"]
}

# Cross-region automated backup replication
resource "aws_db_instance_automated_backups_replication" "dr" {
  source_db_instance_arn = aws_db_instance.production.arn
  kms_key_id             = aws_kms_key.dr_rds.arn
  retention_period       = 14
}

# Aurora Backtrack (MySQL-compatible Aurora only)
resource "aws_rds_cluster" "aurora_production" {
  cluster_identifier      = "aurora-production"
  engine                  = "aurora-mysql"
  engine_version          = "8.0.mysql_aurora.3.05.2"
  backtrack_window        = 86400  # 24 hours of backtrack
  backup_retention_period = 35
  preferred_backup_window = "03:00-04:00"
  storage_encrypted       = true
}

# Manual snapshot with cross-region copy
aws rds create-db-snapshot \
  --db-instance-identifier production-pg \
  --db-snapshot-identifier pre-migration-$(date +%Y%m%d)

aws rds copy-db-snapshot \
  --source-db-snapshot-identifier arn:aws:rds:eu-west-1:123456789:snapshot:pre-migration-20260412 \
  --target-db-snapshot-identifier pre-migration-20260412-dr \
  --source-region eu-west-1 \
  --region us-east-1 \
  --kms-key-id arn:aws:kms:us-east-1:123456789:key/dr-key-id

Azure — гибкий сервер

База данных Azure для гибких серверов PostgreSQL и MySQL включает автоматическое резервное копирование с использованием локально или геоизбыточного хранилища. Геоизбыточное резервное копирование позволяет выполнять межрегиональное восстановление для аварийного восстановления.

# Azure Flexible Server with geo-redundant backup (Terraform)
resource "azurerm_postgresql_flexible_server" "production" {
  name                = "production-pg"
  location            = "westeurope"
  resource_group_name = azurerm_resource_group.db.name
  sku_name            = "GP_Standard_D4s_v3"
  version             = "16"
  storage_mb          = 524288  # 512 GB

  backup_retention_days        = 35
  geo_redundant_backup_enabled = true

  authentication {
    active_directory_auth_enabled = true
    password_auth_enabled         = false
  }
}

# Azure Blob immutability for self-managed backups
resource "azurerm_storage_management_policy" "backup_lifecycle" {
  storage_account_id = azurerm_storage_account.backups.id

  rule {
    name    = "backup-tiering"
    enabled = true
    filters {
      blob_types   = ["blockBlob"]
      prefix_match = ["pg-backups/"]
    }
    actions {
      base_blob {
        tier_to_cool_after_days_since_modification_greater_than    = 30
        tier_to_archive_after_days_since_modification_greater_than = 90
        delete_after_days_since_modification_greater_than          = 2555
      }
    }
  }
}

GCP — Облако SQL

Cloud SQL обеспечивает автоматическое резервное копирование и восстановление на определенный момент времени прямо из коробки. Для самоуправляемых баз данных на GCE или GKE GCS с классами хранения Nearline и Coldline обеспечивает экономичное долгосрочное хранилище резервных копий.

# Cloud SQL with automated backups and PITR (Terraform)
resource "google_sql_database_instance" "production" {
  name             = "production-pg"
  database_version = "POSTGRES_16"
  region           = "europe-west1"

  settings {
    tier = "db-custom-4-16384"

    backup_configuration {
      enabled                        = true
      start_time                     = "03:00"
      point_in_time_recovery_enabled = true
      transaction_log_retention_days = 7
      backup_retention_settings {
        retained_backups = 30
        retention_unit   = "COUNT"
      }
    }

    ip_configuration {
      ssl_mode = "ENCRYPTED_ONLY"
    }
  }
}

# Export to GCS for long-term retention
gcloud sql export sql production-pg \
  gs://pg-backups-longterm/export-$(date +%Y%m%d).sql.gz \
  --database=production_db \
  --offload

Проверка резервной копии и тестирование восстановления

Резервная копия, которая никогда не тестировалась, не является резервной копией — это надежда. Автоматическое тестирование восстановления должно проводиться регулярно, в идеале еженедельно, в изолированной среде. Тест должен подтвердить не только то, что восстановление завершено без ошибок, но и то, что восстановленные данные непротиворечивы и что приложение может подключиться и запросить их.

#!/bin/bash
# verify-backup.sh — Automated backup verification script
set -euo pipefail

RESTORE_DIR="/tmp/backup-verify-$(date +%Y%m%d-%H%M%S)"
LOG_FILE="/var/log/backup-verify.log"
SLACK_WEBHOOK="${SLACK_WEBHOOK_URL}"
DB_TYPE="${1:-postgresql}"  # postgresql or mysql

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"; }
alert() {
  log "ALERT: $*"
  curl -s -X POST "$SLACK_WEBHOOK" \
    -H 'Content-Type: application/json' \
    -d "{\"text\":\"BACKUP VERIFY FAILED: $*\"}"
}

cleanup() {
  log "Cleaning up $RESTORE_DIR"
  rm -rf "$RESTORE_DIR"
  if [ "$DB_TYPE" = "postgresql" ]; then
    pg_ctlcluster 16 verify stop 2>/dev/null || true
  else
    mysqladmin -S /tmp/mysql-verify.sock shutdown 2>/dev/null || true
  fi
}
trap cleanup EXIT

mkdir -p "$RESTORE_DIR"

if [ "$DB_TYPE" = "postgresql" ]; then
  log "Starting PostgreSQL backup verification"

  # Restore latest pgBackRest backup to temporary directory
  pgbackrest --stanza=production \
    --pg1-path="$RESTORE_DIR/pgdata" \
    --type=immediate \
    --target-action=promote \
    restore 2>&1 | tee -a "$LOG_FILE"

  if [ ${PIPESTATUS[0]} -ne 0 ]; then
    alert "pgBackRest restore failed"
    exit 1
  fi

  # Start PostgreSQL on a different port
  pg_ctlcluster 16 verify start -- \
    -D "$RESTORE_DIR/pgdata" \
    -o "-p 5433" \
    -o "-c listen_addresses=127.0.0.1"

  sleep 5

  # Verify data integrity
  TABLES=$(psql -p 5433 -d production_db -t -c \
    "SELECT count(*) FROM information_schema.tables WHERE table_schema='public';")
  log "Verified $TABLES tables exist"

  ROW_CHECK=$(psql -p 5433 -d production_db -t -c \
    "SELECT count(*) FROM orders WHERE created_at > now() - interval '7 days';")
  log "Recent orders count: $ROW_CHECK"

  if [ "$ROW_CHECK" -lt 1 ]; then
    alert "PostgreSQL restore has no recent data — possible stale backup"
    exit 1
  fi

  # Run pg_amcheck for corruption detection (PostgreSQL 14+)
  pg_amcheck -p 5433 -d production_db --heapallindexed 2>&1 | tee -a "$LOG_FILE"

  log "PostgreSQL backup verification PASSED"

else
  log "Starting MySQL backup verification"

  # Prepare and restore latest XtraBackup
  LATEST_FULL=$(ls -td /backups/full-* | head -1)
  cp -r "$LATEST_FULL" "$RESTORE_DIR/mysql-data"
  xtrabackup --prepare --target-dir="$RESTORE_DIR/mysql-data"

  # Start MySQL on a different socket and port
  mysqld --datadir="$RESTORE_DIR/mysql-data" \
    --socket=/tmp/mysql-verify.sock \
    --port=3307 \
    --skip-networking=0 \
    --bind-address=127.0.0.1 &

  sleep 10

  # Verify data
  TABLES=$(mysql -S /tmp/mysql-verify.sock -e \
    "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='production_db';" -sN)
  log "Verified $TABLES tables exist"

  mysqlcheck -S /tmp/mysql-verify.sock --all-databases --check 2>&1 | tee -a "$LOG_FILE"

  log "MySQL backup verification PASSED"
fi

curl -s -X POST "$SLACK_WEBHOOK" \
  -H 'Content-Type: application/json' \
  -d "{\"text\":\"Backup verification PASSED for $DB_TYPE at $(date)\"}"

log "Verification complete"

Планирование аварийного восстановления: RTO и RPO

Каждая стратегия резервного копирования должна разрабатываться с учетом двух показателей:Целевое время восстановления (RTO)— как долго вы можете позволить себе простоя — иЦелевая точка восстановления (RPO)— сколько данных вы можете позволить себе потерять. Эти цифры определяют каждое решение о частоте, методе и архитектуре резервного копирования.

СценарийRTORPOСтратегия
Оформление заказа в электронной торговле< 5 мин0 (нулевая потеря данных)Синхронная репликация + непрерывное архивирование WAL + аварийное переключение в горячем резерве
Приложение SaaS< 30 мин.< 1 мин.Потоковая репликация + непрерывное архивирование WAL-G + автоматическое переключение при сбое
Внутренние инструменты< 4 часа< 1 часЕжедневная разница + почасовая инкрементация + архивация WAL
Аналитика/хранилище данных< 24 часа< 24 часаЕжедневное полное резервное копирование в облачное хранилище
Разработка/постановка< 48 часов< 1 неделяЕженедельное полное резервное копирование

Для нулевого RPO необходима синхронная репликация хотя бы на один резервный сервер. Это увеличивает задержку для каждой транзакции записи, но гарантирует, что ни одна зафиксированная транзакция не будет потеряна. Большинство производственных систем допускают почти нулевое значение RPO (потенциальные потери в секундах) за счет использования асинхронной потоковой репликации с непрерывным архивированием WAL/binlog, что позволяет избежать штрафов за задержку записи.

Шаблон Runbook аварийного восстановления

# DR Runbook: Database Recovery

## Severity Levels
- P1: Complete data loss / corruption — all hands, CEO notified
- P2: Partial data loss / single region down — on-call team + escalation
- P3: Replica failure / backup failure — on-call investigation

## Recovery Procedures

### Scenario A: Primary DB failure, replicas healthy
1. Promote replica to primary (automated via Patroni / orchestrator)
2. Verify application connectivity
3. Re-establish replication from new primary
4. Investigate root cause

### Scenario B: Complete cluster failure, backups intact
1. Provision new database infrastructure
2. Restore latest full backup
3. Apply WAL/binlog to reach latest consistent point
4. Verify data integrity with checksums
5. Update DNS / connection strings
6. Resume application traffic
7. Re-establish backup schedule immediately

### Scenario C: Data corruption (bad migration / SQL injection)
1. Identify exact timestamp of corruption
2. Restore to point-in-time just before corruption
3. Export affected tables from restored copy
4. Merge clean data into production
5. OR: full PITR restore if corruption is widespread

## Contacts
- DBA on-call: [PagerDuty rotation]
- Infrastructure: [PagerDuty rotation]
- VP Engineering: [phone number]

## Validation Checklist
- [ ] Application health checks pass
- [ ] Row counts match expected ranges
- [ ] Recent transactions are present
- [ ] Replication re-established
- [ ] Backup schedule resumed
- [ ] Post-incident review scheduled

Мониторинг резервного копирования и оповещение

Системы резервного копирования

выходят из строя автоматически. База данных продолжает работать, приложение продолжает обслуживать трафик, и никто не замечает, что резервные копии перестали работать три недели назад — пока они им не понадобятся. Проактивный мониторинг имеет важное значение.

# Prometheus alerting rules for backup monitoring
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: backup-alerts
  namespace: monitoring
spec:
  groups:
    - name: database-backups
      rules:
        - alert: BackupTooOld
          expr: |
            (time() - backup_last_successful_timestamp_seconds) > 90000
          for: 10m
          labels:
            severity: critical
          annotations:
            summary: "Database backup is older than 25 hours"
            description: "Last successful backup for {{ $labels.database }} was {{ $value | humanizeDuration }} ago"

        - alert: BackupJobFailed
          expr: |
            kube_job_status_failed{job_name=~".*backup.*"} > 0
          for: 5m
          labels:
            severity: critical
          annotations:
            summary: "Backup CronJob failed: {{ $labels.job_name }}"

        - alert: WALArchivingLagging
          expr: |
            pg_stat_archiver_failed_count > 0
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: "PostgreSQL WAL archiving has failures"

        - alert: BackupStorageQuotaNearing
          expr: |
            (backup_storage_used_bytes / backup_storage_quota_bytes) > 0.85
          for: 30m
          labels:
            severity: warning
          annotations:
            summary: "Backup storage at {{ $value | humanizePercentage }} capacity"

        - alert: BinlogSpaceCritical
          expr: |
            mysql_binlog_size_bytes > 53687091200
          for: 10m
          labels:
            severity: warning
          annotations:
            summary: "MySQL binlog space exceeds 50GB — check archiving"
# Custom Prometheus exporter for pgBackRest metrics
#!/usr/bin/env python3
"""pgBackRest Prometheus exporter — exposes backup age and size metrics."""
import json
import subprocess
import time
from prometheus_client import start_http_server, Gauge

BACKUP_AGE = Gauge('pgbackrest_last_backup_age_seconds', 'Seconds since last backup', ['stanza', 'type'])
BACKUP_SIZE = Gauge('pgbackrest_last_backup_size_bytes', 'Size of last backup', ['stanza', 'type'])
BACKUP_REPO_SIZE = Gauge('pgbackrest_repo_size_bytes', 'Total repository size', ['stanza'])

def collect():
    result = subprocess.run(
        ['pgbackrest', '--output=json', 'info'],
        capture_output=True, text=True
    )
    info = json.loads(result.stdout)
    for stanza_info in info:
        stanza = stanza_info['name']
        for backup in stanza_info.get('backup', []):
            backup_type = backup['type']
            stop_time = backup['timestamp']['stop']
            age = time.time() - stop_time
            BACKUP_AGE.labels(stanza=stanza, type=backup_type).set(age)
            size = backup['info']['size']
            BACKUP_SIZE.labels(stanza=stanza, type=backup_type).set(size)

if __name__ == '__main__':
    start_http_server(9854)
    while True:
        collect()
        time.sleep(300)

Распространенные ошибки и антипаттерны

После управления резервными копиями баз данных в десятках производственных сред именно эти ошибки наносят наибольший ущерб.

1. Резервное копирование на тот же диск, что и база данных.Если диск выйдет из строя, вы потеряете и базу данных, и резервную копию. Всегда записывайте резервные копии в отдельное хранилище — в идеале за пределами хоста и региона.

2. Никогда не тестировать восстановление.Резервная копия, которую невозможно восстановить, не является резервной копией. Запланируйте автоматическое тестирование восстановления еженедельно, а инженеры ежеквартально выполняют тестирование ручного восстановления.

3. Использование исключительно репликации в качестве резервной копии. Репликацияне является резервной.DROP TABLEна первичном сервере мгновенно реплицируется на все реплики. Репликация защищает от аппаратных сбоев, а не от логических ошибок.

4. Не отслеживаются задания резервного копирования. ЗаданияCron завершаются автоматически. Kubernetes CronJobs приостанавливается. Срок действия учетных данных S3 истекает. Каждое задание резервного копирования должно сообщать об успешном или неудачном выполнении в систему мониторинга и выдавать предупреждение, если последняя успешная резервная копия старше вашего RPO.

5. Хранение ключей шифрования вместе с резервными копиями.Если злоумышленник получит доступ к вашему хранилищу резервных копий, у него также не должно быть ключа расшифровки. Храните ключи в специальном менеджере секретов.

6. Политика хранения отсутствует.Без политик жизненного цикла хранилище резервных копий растет без ограничений. Определите четкие сроки хранения: 7 дней для сегментов WAL, 30 дней для ежедневных резервных копий, 12 месяцев для ежемесячных резервных копий и автоматизируйте их удаление.

7. Игнорирование влияния на производительность резервного копирования.Выполнение полного резервного копирования основной базы данных в часы пик снижает производительность приложения. Планируйте резервное копирование в периоды с низким трафиком или выполняйте резервное копирование из выделенной реплики.

8. Использованиеmysqldumpдля больших баз данных без--single-transaction.Без этого флагаmysqldumpблокирует таблицы, блокируя запись на время дампа. Для больших баз данных это может означать минуты или часы простоя.

9. Забыли сделать резервную копию конфигурации базы данных.Восстановление данных – это только полдела. Если вы потеряетеpostgresql.conf,pg_hba.conf,my.cnf, настройки репликации и пользовательские разрешения, вы не сможете вернуть базу данных в работоспособное состояние. Включите файлы конфигурации в процесс резервного копирования.

10. Процедура восстановления не документирована.Во время сбоя человек, восстанавливающий базу данных, может не быть человеком, создавшим резервные копии. Написанный и протестированный модуль Runbook имеет решающее значение.

Оптимизация затрат на хранилище резервных копий

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

Используйте инкрементное/дифференциальное резервное копирование.Еженедельные полные резервные копии и ежедневные дифференциальные резервные копии используют часть хранилища по сравнению с ежедневными полными резервными копиями. Возможность дельта-восстановления pgBackRest означает, что инкрементальные резервные копии восстанавливаются почти так же быстро, как и полные резервные копии.

Включить сжатие.Современные алгоритмы сжатия, такие как zstd, обеспечивают превосходную степень сжатия (от 5:1 до 10:1 для типичных данных базы данных) с минимальными издержками CPU. И pgBackRest, и XtraBackup изначально поддерживают zstd.

Внедрение многоуровневого хранения данных.Перемещайте резервные копии на более дешевые уровни хранения по мере их устаревания. Показанные ранее политики жизненного цикла (S3 Standard → IA → Glacier, GCS Standard → Nearline → Coldline) позволяют снизить затраты на долгосрочное хранение на 70–90%.

Дедупликация, где это возможно.pgBackRest использует дедупликацию на уровне блоков в своем репозитории, сохраняя только измененные блоки в резервных копиях. Это значительно сокращает объем хранилища для баз данных, в которых большая часть данных является статической.

Ретенционные окна подходящего размера.Многие команды из соображений безопасности по умолчанию хранят резервные копии навсегда. Проанализируйте фактические шаблоны восстановления и требования соответствия, а затем установите соответствующий срок хранения. Требование хранения в течение 7 лет позволяет использовать глубокое архивное хранилище по цене менее 1 доллара США за ТБ в месяц у большинства облачных провайдеров.

# Cost comparison: Full vs Incremental backup storage
# Assuming 500 GB database, 5% daily change rate, 30-day retention

# Strategy A: Daily full backups
# 500 GB × 30 days = 15,000 GB = 15 TB
# S3 Standard: 15 TB × $0.023/GB = $345/month

# Strategy B: Weekly full + daily incremental
# 4 full × 500 GB = 2,000 GB
# 26 incremental × 25 GB = 650 GB
# Total: 2,650 GB ≈ 2.6 TB
# S3 Standard: 2.6 TB × $0.023/GB = $59.80/month

# Strategy C: Strategy B + lifecycle tiering
# Current week: 525 GB Standard = $12.08
# Weeks 2-4: 2,125 GB Standard-IA = $26.56
# Total: $38.64/month

# Savings: Strategy C is 89% cheaper than Strategy A

Собираем все вместе: полная архитектура резервного копирования

Ниже представлена рекомендуемая архитектура резервного копирования для производственной среды, на которой работают как MySQL, так и PostgreSQL, развернутая на Kubernetes с возможностью аварийного восстановления в нескольких облаках.

Для PostgreSQL:

  • pgBackRest в качестве основного инструмента резервного копирования с двумя репозиториями (S3 + Azure Blob)
  • Непрерывное архивирование WAL в оба репозитория
  • Еженедельное полное резервное копирование + ежедневная разность (через K8s CronJob)
  • Снимки тома Longhorn каждые 4 часа для быстрого отката
  • Автоматическая проверка восстановления каждую среду
  • Мониторинг Prometheus с оповещениями о возрасте резервной копии, сбоях и объеме хранилища

Для MySQL:

  • Percona XtraBackup для потоковой передачи физических резервных копий на S3
  • Непрерывная доставка двоичного журнала в отдельное хранилище
  • Еженедельный полный + ежедневный инкрементальный (через K8s CronJob)
  • Dailymysqldumpкритических схем для портативных логических резервных копий
  • Снимки тома Longhorn каждые 4 часа
  • Автоматическая проверка восстановления каждый четверг

Для кластера Kubernetes:

  • Ежедневное резервное копирование пространств имен базы данных Velero со снимками PV
  • RKE2/k3s и т. д. каждые 6 часов создает снимки в хранилище вне кластера
  • Репозиторий GitOps как источник истины для всех манифестов

Для аварийного восстановления:

  • Межрегиональная репликация S3 в регион DR
  • Azure GRS для геоизбыточных резервных копий
  • Ежемесячная проверка аварийного восстановления: полное восстановление кластера из резервных копий в регионе аварийного восстановления
  • Документированный модуль Runbook с деревом решений для каждого сценария отказа

Заключение

Резервные копии баз данных — это последняя линия защиты вашего бизнеса от катастрофической потери данных. Стратегии, изложенные в этой статье — физическое и логическое резервное копирование, непрерывное архивирование WAL и binlog, многооблачное хранилище с политиками жизненного цикла, шифрование на каждом уровне, автоматическое планирование с помощью Kubernetes CronJobs и систематическая проверка восстановления — представляют собой современное состояние производственных сред MySQL и PostgreSQL.

Самый важный вывод заключается в следующем: стратегия резервного копированиятак же хороша, как и ее последний успешный тест восстановления. Каждый инструмент, сценарий и шаблон архитектуры в этой статье предназначены для одной цели — гарантировать, что в худшем случае вы сможете восстановить свои данные, выполнить свои обязательства по RTO и RPO и сохранить работу своего бизнеса. Создайте свою систему резервного копирования, автоматизируйте ее, контролируйте, тестируйте, а затем тестируйте еще раз. Ваше будущее «я» скажет вам спасибо.