Workstation Logo
Productos
Labs de IAAgentes OpenAIAgentes ClaudeGrok BotWorkstation CRM (WSL CRM)MarketingTodos los Productos
Soluciones IA
Estaciones de Trabajo IAAI SME PackagesIA PrivadaClústeres GPUIA en el BordeLaboratorio IA EmpresarialIA por Industria
Servicios
Modernización de plataformaIngeniería digitalFundamentos de datos e IAOperaciones autónomasConsultoría de IAAutomatización DevOpsCiberseguridadDesarrollo de softwareCreación de agentesConfiguración MLOps
Sobre Nosotros
SociosHistorias de Clientes
Artículos
Documentación
WSL ProxyRing PromoterWSL VaultJobshoutSysOps 24/7
Blog
ContáctenosLogin
Workstation

Estaciones de trabajo de IA, software multiagente de IA, infraestructura de GPU y soluciones de agentes inteligentes para empresas modernas.

Contáctenos

Soluciones de IA

Estaciones de Trabajo IAAI SME PackagesIA PrivadaClústeres GPUIA en el BordeLaboratorio IA EmpresarialIA por Industria

Productos

Todos los ProductosWSL CRM y ERPMarketingAgentes OpenAIWSL ProxyRing PromoterWSL VaultJobshoutSysOps 24/7

Empresa

Sobre NosotrosPor qué WorkstationSociosHistorias de ClientesPreciosContacto

Recursos

ArtículosDocumentaciónBlogBuscarMapa del Sitio
Oficina Reino Unido
77-79 Marlowes, Hemel Hempstead HP1 1LFCómo llegar: tome la salida 20 de la M25, Outer LondonN.º de empresa: 11641870Lun - Vie: 9:00 - 18:00 GMT
+44 7515 356 146
Oficina Bélgica
Workstation SRL, Rue Vanderkindere 34, 1180 Uccle, BrusselsBE 0751.518.683Lun - Vie: 9:00 - 18:00 CET
+32 492 45 67 46
Oficina India
#159 Sector 9, Pocket 1, DDA Flats, 110077 Dwarka, New Delhi
+91 98881 98841

© 2026 Workstation AI. Todos los derechos reservados.

PrivacidadCookiesTérminos de ServicioMapa del sitio web

Loading blog...

Home / Blog
DatabaseDevOpsKubernetesBackend

Estrategias de copia de seguridad de bases de datos de producción que realmente funcionan: MySQL y PostgreSQL

Estrategias comprobadas de copia de seguridad y recuperación para MySQL y PostgreSQL en producción

Balinder Walia12 de abril de 202634 min read

La pérdida de datos de producción es el tipo de incidente que acaba con carreras, cierra empresas y aparece en la portada de Hacker News por todas las razones equivocadas. Sin embargo, la mayoría de los equipos tratan las copias de seguridad de las bases de datos como una ocurrencia tardía: un trabajo cron que alguien creó hace dos años y que nadie ha verificado desde entonces. Este artículo presenta estrategias de respaldo probadas en batalla para MySQL y PostgreSQL que han sido probadas en entornos de producción que van desde clústeres k3s de un solo nodo hasta implementaciones de nube multirregionales que procesan millones de transacciones diariamente.

Cubriremos todo el espectro: métodos de respaldo físico y lógico, recuperación en un momento dado, programación automatizada, objetivos de almacenamiento en la nube, cifrado, verificación, enfoques nativos de Kubernetes y la planificación de recuperación ante desastres que lo une todo. Cada recomendación viene con una configuración y un código concretos que puede adaptar a su entorno.

Descripción de los tipos de copia de seguridad

Antes de sumergirse en herramientas específicas, necesita un modelo mental claro de las cuatro estrategias de respaldo fundamentales y cómo interactúan con los objetivos de recuperación. Cada estrategia establece un compromiso diferente entre la velocidad de respaldo, el consumo de almacenamiento y el tiempo de recuperación.

Una copia de seguridad completacaptura toda la base de datos en un único momento. Es el más sencillo de entender y el más rápido de restaurar, pero también el más caro en almacenamiento y el más lento de crear. Una copia de seguridad incrementalcaptura solo los datos que han cambiado desde la última copia de seguridad de cualquier tipo. Es rápido de crear y compactar en el almacenamiento, pero la restauración requiere reproducir la cadena completa: la última copia de seguridad completa más cada incremental posterior. Una copia de seguridad diferencialcaptura todo lo que ha cambiado desde la última copia de seguridad completa. Ocupa un término medio: más grande que un incremental pero más sencillo de restaurar porque solo necesita el último completo más el último diferencial. Finalmente, el archivo continuo(archivo WAL en PostgreSQL, transmisión de registros binarios en MySQL) captura cada transacción individual a medida que ocurre, lo que permite la recuperación en un momento dado en cualquier momento entre copias de seguridad.

Descripción general de la estrategia de copia de seguridad: completa, incremental, diferencial o continuaDía 0Día 1Día 2Día 3Día 4Día 5CompletoIncr.Diferencial.WAL/BinlogCOMPLETO (100%)COMPLETO (100%)+5%+3%+4%+2%+5%+8%+12%+14%WAL continuo / flujo de registro binario (cada transacción)Objetivo de recuperaciónCopia de seguridad completaIncrementalDiferencialTransmisión WAL/BinlogPunto de recuperación

La estrategia óptima para la mayoría de los sistemas de producción es una combinación: copias de seguridad completas semanales, incrementales o diferenciales diarios y archivado WAL/binlog continuo. Esto le brinda una recuperación rápida de las copias de seguridad completas recientes y la capacidad de recuperarse en cualquier momento cuando lo necesite.

MySQL Métodos de copia de seguridad

MySQL ofrece varias herramientas de respaldo, cada una adaptada a diferentes tamaños de bases de datos y requisitos de recuperación. La elección correcta depende de su volumen de datos, ventana de respaldo aceptable y objetivos de RTO/RPO.

mysqldump: la copia de seguridad lógica universal

mysqldumpproduce declaraciones SQL que recrean el esquema y los datos. Funciona en todas las versiones y motores de almacenamiento de MySQL, lo que lo convierte en el recurso universal. Sin embargo, bloquea las tablas durante el volcado (a menos que se use--single-transactioncon InnoDB) y la velocidad de restauración se degrada significativamente para bases de datos de más de 50 a 100 GB porque reproduce declaraciones INSERT individuales.

# 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 — Copia de seguridad lógica paralela

mysqlpumpmejora amysqldumpcon volcado de tablas paralelo y compresión incorporada. Puede reducir significativamente el tiempo de copia de seguridad de bases de datos con muchas tablas independientes.

# 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 — Copias de seguridad físicas para InnoDB

Para bases de datos de más de 50 GB, las copias de seguridad lógicas se vuelven poco prácticas: tanto la ventana de copia de seguridad como el tiempo de restauración crecen linealmente con el tamaño de los datos. Percona XtraBackup toma copias de nivel físico de archivos de datos InnoDB sin bloquear la base de datos, lo que lo hace adecuado para implementaciones de varios terabytes.

# 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

Registro binario MySQL: recuperación en un momento dado

Los registros binarios MySQL registran cada declaración de modificación de datos o cambio de fila. Cuando se combinan con una copia de seguridad completa o física, permiten la recuperación en un momento dado en cualquier momento después de que se realizó la copia de seguridad.

# 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 Métodos de copia de seguridad

El ecosistema de respaldo de PostgreSQL es posiblemente más rico que el de MySQL, con herramientas propias y un conjunto maduro de soluciones comunitarias diseñadas específicamente para entornos de producción a gran escala.

pg_dump y pg_dumpall — Copias de seguridad lógicas

Al igual quemysqldump,pg_dumpproduce copias de seguridad lógicas. El formato personalizado (-Fc) es el predeterminado recomendado porque admite restauración paralela, restauración selectiva de tablas y compresión integrada.

# 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 — Base de respaldo físico

pg_basebackuptoma una copia física de todo el directorio de datos PostgreSQL. Es la base para la configuración de replicación de transmisión y recuperación independiente. Combinado con el archivo WAL, permite la recuperación en un momento dado.

# 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: gestión de copias de seguridad de nivel empresarial

pgBackRest es el estándar de oro para la gestión de copias de seguridad de PostgreSQL. Admite copias de seguridad completas, incrementales y diferenciales, copia de seguridad y restauración paralelas, cifrado, destinos de múltiples repositorios (disco local, S3, GCS, Azure Blob) y archivado WAL automatizado, todo a través de una configuración única y cohesiva.

# /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: Archivado WAL ligero en almacenamiento en la nube

WAL-G es una alternativa más sencilla a pgBackRest que se centra en la transmisión de segmentos WAL y copias de seguridad básicas al almacenamiento de objetos en la nube. Es popular en entornos en contenedores donde desea un único binario con una configuración mínima.

# 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: servidor de respaldo centralizado

Barman (Administrador de copias de seguridad y recuperación) está diseñado para entornos donde un servidor de copias de seguridad dedicado gestiona copias de seguridad para múltiples instancias PostgreSQL. Admite protocolos de replicación de streaming y rsync/SSH para el transporte de copias de seguridad.

# /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

Recuperación de un punto en el tiempo (PITR)

La recuperación en un momento dado es la capacidad más importante de su kit de herramientas de respaldo. Le permite restaurar una base de datos al estado exacto en el que se encontraba en cualquier momento específico, no sólo cuando se realizaron las copias de seguridad, sino en cualquier segundo entre copias de seguridad. Esto es fundamental para recuperarse de una eliminación accidental de datos, errores de aplicaciones que corrompen los datos e incidentes de seguridad en los que es necesario identificar el momento exacto del compromiso.

Cronología de recuperación de un punto en el tiempo (PITR)00:00Sol06:0012:0018:0000:00lunesCopia de seguridad completapg_basebackup@ 00:00WAL/Segmentos de registro binario (continuo)✖MESA ABATIBLE@ 16:42:31Objetivo de recuperación@ 16:42:301. Restaurarcompleto2. Reproducir WAL para apuntar a3. ¡DB recuperada!PITR = Restaurar la última copia de seguridad completa + Reproducir segmentos WAL/binlog hasta 1 segundo antes del desastreGranularidad de recuperación: por transacción (PostgreSQL WAL) o por segundo (MySQL binlog)

PITR para PostgreSQL

PostgreSQL PITR funciona restaurando una copia de seguridad base y reproduciendo segmentos WAL hasta la marca de tiempo de destino. Con pgBackRest, todo el proceso es un solo comando.

# 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 para MySQL

MySQL PITR combina una restauración física XtraBackup con reproducción de registros binarios.

# 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

Arquitectura de copia de seguridad multinube

Las estrategias de respaldo de producción deben tener en cuenta las fallas de cualquier proveedor o región de nube. Almacenar copias de seguridad exclusivamente en la misma cuenta de nube y región que su base de datos de producción significa que una sola cuenta comprometida, un problema de facturación o una interrupción regional pueden eliminar tanto sus datos como sus copias de seguridad simultáneamente. Una arquitectura sólida envía copias de seguridad a al menos dos destinos de almacenamiento independientes con replicación entre regiones.

Arquitectura de copia de seguridad multinubePostgreSQLPrimario + RéplicasMySQLPrimario + RéplicasCapa de cifradoAES-256-CBCTLS en tránsitoSSE-S3 / SSE-KMSen reposoCifrado del lado del clientea través de pgBackRest/ WAL-GAWS S3eu-west-1 (primario)Ciclo de vida de: IA → GlaciarAzure BlobEuropa occidental (primaria)Políticas de inmutabilidadAlmacenamiento en la nube de Googleeuropa-oeste1 (primario)Cerca de línea → Línea fríaS3 entre regionesnosotros-este-1 (DR)Azure GRSNorte de Europa (DR)GCS multirregiónUE multirregión (DR)Monitoreo y monitoreo de respaldoAlertaMétricas de Prometheus • Paneles de control Grafana • Alertas de PagerDuty/Slack sobre fallas en la copia de seguridad o umbral de antigüedadFlechas sólidas = flujo de respaldoFlechas discontinuas = replicación entre regionesCuadro discontinuo = límite de cifrado

Configuración de almacenamiento en la nube con políticas de ciclo de vida

# 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

Copia de seguridad, cifrado y seguridad

Las copias de seguridad

son un objetivo de gran valor para los atacantes. Una copia de seguridad robada y sin cifrar le brinda al atacante una copia completa de sus datos de producción sin necesidad de vulnerar sus sistemas en ejecución. Cada copia de seguridad, en tránsito y en reposo, debe estar cifrada.

Cifrado en tránsitosignifica usar TLS para todas las conexiones entre el servidor de la base de datos y el destino de la copia de seguridad. Tanto pgBackRest como XtraBackup transmiten a través de canales cifrados cuando se configuran con TLS. Cuando se envía a S3, Azure Blob o GCS, los SDK del cliente usan HTTPS de forma predeterminada.

Cifrado en reposotiene dos capas. El cifrado del lado del servidor (SSE) cifra los datos después de que llegan al destino de almacenamiento: S3 SSE-KMS, Azure Storage Service Encryption o cifrado predeterminado de GCS. El cifrado del lado del cliente cifra los datos antes de que abandonen el servidor de la base de datos, lo que garantiza que el proveedor de la nube nunca vea datos en texto sin formato. pgBackRest y WAL-G admiten el cifrado del lado del cliente de forma nativa.

# 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)

Almacene las claves de cifrado por separado de las propias copias de seguridad. El enfoque recomendado es un administrador de secretos como HashiCorp Vault, AWS Secrets Manager o Azure Key Vault. Si almacena la clave junto con la copia de seguridad, un atacante que obtenga acceso a su almacenamiento de copia de seguridad tendrá todo lo que necesita.

Programación de copia de seguridad automatizada

Las copias de seguridad manuales no son copias de seguridad, son aspiraciones. Los programas de respaldo deben automatizarse, monitorearse y alertar en caso de falla.

Cron del sistema para Bare Metal y VM

# /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 Trabajos cronológicos

En entornos Kubernetes, CronJobs reemplaza el cron del sistema. Ofrecen lógica de reintento integrada, control de concurrencia e integración con RBAC del clúster y gestión de secretos.

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: enfoques de copia de seguridad nativa

La ejecución de bases de datos en Kubernetes introduce una nueva dimensión a la estrategia de respaldo. Además de las copias de seguridad de bases de datos a nivel de aplicación, debe considerar la copia de seguridad a nivel de clúster (etcd), las instantáneas de volumen persistentes y las copias de seguridad administradas por el operador.

Kubernetes Tubería de respaldoClúster Kubernetes (k3s / RKE2)Trabajo cronológicoHorario: 0 1 * * *Módulo de respaldopgRespaldo /Contenedor XtraBackupPostgreSQL CápsulaRéplica StatefulSet 0PVC: datos de páginaMySQL CápsulaRéplica StatefulSet 0PVC: datos mysqlBocina larga CSIInstantáneas fotovoltaicas + RéplicasVolumen Instantánea CRDVeleroCopia de seguridad a nivel de clústeretcd + espacios de nombres + PVAlmacenamiento de objetosS3 / GCS / Azure Blob / MinIOcifrado y cifradoversionadoNiveles del ciclo de vida habilitadosCopias de seguridad de base de datos+ WALVeleroObjetivo Longhorn S3Prometheus + GrafanaMétricas de trabajos de respaldo + alertasTasa de éxito/fracaso de CronJobRuta de restauración1. Restauración de Velero (clúster)2. pgBackRest/XtraBackup (datos)3. Reversión de instantáneas de LonghornProgramadorAgente de copia de seguridadPostgreSQLMySQLVeleroBocina largaAlmacenamiento de objetos

Velero para copia de seguridad a nivel de clúster

Velero realiza una copia de seguridad de los recursos Kubernetes (implementaciones, servicios, mapas de configuración, secretos) y volúmenes persistentes. No reemplaza las copias de seguridad de bases de datos a nivel de aplicación: captura una instantánea de los PV que no son consistentes con fallas, lo que puede no ser consistente desde el punto de vista transaccional para las bases de datos. Utilice Velero para la recuperación de clústeres y herramientas a nivel de aplicación (pgBackRest, XtraBackup) para la recuperación de bases de datos.

# 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
Instantáneas de Longhorn

en k3s

Las implementaciones de

k3s suelen utilizar Longhorn como proveedor de almacenamiento CSI. Longhorn proporciona instantáneas a nivel de volumen y la capacidad de replicar instantáneas en un almacenamiento de objetos compatible con S3. Para las bases de datos, combine instantáneas de Longhorn con copias de seguridad a nivel de aplicación para una defensa en profundidad.

# 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

Copias de seguridad administradas por el operador

Los operadores de bases de datos como CloudNativePG (para PostgreSQL) y Percona Operador (para MySQL) integran la gestión de copias de seguridad directamente en el ciclo de vida de la base de datos. El operador maneja la programación, el archivado WAL y la retención automáticamente a través de recursos personalizados.

# 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

Estrategias específicas del proveedor de nube

AWS — RDS y Aurora

AWS RDS proporciona instantáneas diarias automatizadas con retención configurable (hasta 35 días) y copia de seguridad continua mediante el archivo de registros de transacciones para una recuperación en un momento dado. Aurora agrega Backtrack, que puede rebobinar el clúster a cualquier punto dentro de la ventana de retroceso sin requerir una restauración; simplemente invierte el estado interno de la base de datos.

# 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 — Servidor flexible

La base de datos Azure para el servidor flexible PostgreSQL y MySQL incluye copias de seguridad automáticas con almacenamiento con redundancia local o geográfica. La copia de seguridad con redundancia geográfica permite la restauración entre regiones para la recuperación ante desastres.

# 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 — Nube SQL

Cloud SQL proporciona copias de seguridad automatizadas y recuperación en un momento dado listas para usar. Para bases de datos autoadministradas en GCE o GKE, GCS con clases de almacenamiento nearline y coldline proporciona almacenamiento de respaldo rentable a largo plazo.

# 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

Verificación de copia de seguridad y prueba de restauración

Una copia de seguridad que nunca ha sido probada no es una copia de seguridad, es una esperanza. Las pruebas de restauración automatizadas deben ejecutarse según un cronograma regular, idealmente semanalmente, en un entorno aislado. La prueba debe validar no solo que la restauración se complete sin errores, sino que los datos restaurados sean consistentes y la aplicación pueda conectarse y consultarlos.

#!/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"

Planificación de recuperación ante desastres: RTO y RPO

Cada estrategia de respaldo debe diseñarse en torno a dos métricas:Objetivo de tiempo de recuperación (RTO)(cuánto tiempo puede permitirse estar inactivo) yObjetivo de punto de recuperación (RPO): cuántos datos puede permitirse perder. Estos números impulsan todas las decisiones sobre la frecuencia, el método y la arquitectura de las copias de seguridad.

EscenarioRTORPOEstrategia
Pago de comercio electrónico< 5 min0 (pérdida de datos cero)Replicación síncrona + archivado WAL continuo + conmutación por error en espera activa
Aplicación SaaS< 30 minutos< 1 minReplicación de streaming + archivado continuo WAL-G + conmutación por error automatizada
Herramientas internas< 4 horas< 1 horaDiferencial diario + incremental por hora + archivo WAL
Análisis/almacén de datos< 24 horas< 24 horasCopia de seguridad completa diaria en almacenamiento en la nube
Desarrollo/puesta en escena< 48 horas< 1 semanaCopia de seguridad completa semanal

Para un RPO cero, necesita replicación sincrónica al menos en un modo de espera. Esto agrega latencia a cada transacción de escritura pero garantiza que no se pierda ninguna transacción confirmada. La mayoría de los sistemas de producción aceptan RPO (segundos de pérdida potencial) casi nulo mediante el uso de replicación de transmisión asincrónica con archivado WAL/binlog continuo, lo que evita la penalización de latencia de escritura.

Plantilla de runbook de recuperación ante desastres

# 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

Monitoreo y alerta de respaldo

Los sistemas de respaldo fallan silenciosamente. La base de datos sigue funcionando, la aplicación sigue atendiendo tráfico y nadie se da cuenta de que las copias de seguridad dejaron de funcionar hace tres semanas, hasta que necesitan una. El seguimiento proactivo es esencial.

# 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)

Errores comunes y antipatrones

Después de administrar copias de seguridad de bases de datos en docenas de entornos de producción, estos son los errores que causan el mayor daño.

1. Realizar una copia de seguridad en el mismo disco que la base de datos.Si el disco falla, se pierde tanto la base de datos como la copia de seguridad. Escriba siempre las copias de seguridad en un destino de almacenamiento independiente, idealmente fuera del host y fuera de la región.

2. Nunca probar restauraciones.Una copia de seguridad que no se puede restaurar no es una copia de seguridad. Programe pruebas de restauración automatizadas semanalmente y haga que los ingenieros realicen simulacros de restauración manuales trimestralmente.

3. Depender únicamente de la replicación como respaldo.La replicación no es una copia de seguridad. UnDROP TABLEen el principal se replica instantáneamente en todas las réplicas. La replicación protege contra fallas de hardware, no contra errores lógicos.

4. No monitorear trabajos de respaldo.Los trabajos cron fallan silenciosamente. Kubernetes CronJobs se suspenden. Las credenciales de S3 caducan. Cada trabajo de respaldo debe informar el éxito o el fracaso a un sistema de monitoreo y alertar si el respaldo exitoso más reciente es anterior a su RPO.

5. Almacenamiento de claves de cifrado junto con copias de seguridad.Si un atacante obtiene acceso a su almacenamiento de respaldo, no debería tener también la clave de descifrado. Almacene las claves en un administrador de secretos dedicado.

6. Sin política de retención.Sin políticas de ciclo de vida, el almacenamiento de respaldo crece sin límites. Defina ventanas de retención claras: 7 días para segmentos WAL, 30 días para copias de seguridad diarias, 12 meses para copias de seguridad mensuales y automatice su eliminación.

7. Ignorar el impacto en el rendimiento de la copia de seguridad.La ejecución de una copia de seguridad completa en una base de datos principal durante las horas pico degrada el rendimiento de la aplicación. Programe copias de seguridad durante períodos de poco tráfico o realice una copia de seguridad desde una réplica dedicada.

8. Uso demysqldumppara bases de datos grandes sin--single-transaction.Sin este indicador,mysqldumpbloquea las tablas y bloquea las escrituras mientras dure el volcado. Para bases de datos grandes, esto puede significar minutos u horas de inactividad.

9. Olvidar hacer una copia de seguridad de la configuración de la base de datos.Restaurar datos es sólo la mitad de la batalla. Si pierdepostgresql.conf,pg_hba.conf,my.cnf, la configuración de replicación y las concesiones de usuario, no podrá devolver la base de datos a un estado utilizable. Incluya archivos de configuración en su proceso de copia de seguridad.

10. No documentar el procedimiento de restauración.Durante una interrupción, la persona que restaura la base de datos puede no ser la persona que configuró las copias de seguridad. Un runbook escrito y probado es fundamental.

Optimización de costos para almacenamiento de respaldo

Los costos de almacenamiento de respaldo de

pueden crecer rápidamente, especialmente con respaldos completos frecuentes de grandes bases de datos. Estas estrategias mantienen los costos bajo control sin comprometer la recuperabilidad.

Utilice copias de seguridad incrementales/diferenciales.Un diferencial completo semanal más un diferencial diario utiliza una fracción del almacenamiento en comparación con los respaldos completos diarios. La capacidad de restauración delta de pgBackRest significa que las copias de seguridad incrementales se restauran casi tan rápido como las copias de seguridad completas.

Habilitar la compresión.Los algoritmos de compresión modernos como zstd ofrecen excelentes relaciones de compresión (5:1 a 10:1 para datos de bases de datos típicos) con una sobrecarga mínima de CPU. Tanto pgBackRest como XtraBackup admiten zstd de forma nativa.

Implementar almacenamiento en niveles.Mueva las copias de seguridad a niveles de almacenamiento progresivamente más baratos a medida que envejecen. Las políticas de ciclo de vida mostradas anteriormente (Estándar S3 → IA → Glacier, Estándar GCS → Nearline → Coldline) pueden reducir los costos de almacenamiento a largo plazo entre un 70 % y un 90 %.

Deduplicar siempre que sea posible.pgBackRest utiliza la deduplicación a nivel de bloque en su repositorio, almacenando solo los bloques modificados en las copias de seguridad. Esto reduce drásticamente el almacenamiento de bases de datos donde la mayoría de los datos son estáticos.

Ventanas de retención del tamaño adecuado.Muchos equipos mantienen las copias de seguridad para siempre por precaución. Analice sus patrones de recuperación reales y requisitos de cumplimiento, luego establezca la retención que coincida. Un requisito de retención de 7 años puede utilizar almacenamiento de archivos profundo a menos de $1/TB/mes en la mayoría de los proveedores de nube.

# 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

poniéndolo todo junto: una arquitectura de respaldo completa

Esta es la arquitectura de respaldo recomendada para un entorno de producción que ejecuta MySQL y PostgreSQL, implementada en Kubernetes con recuperación ante desastres de múltiples nubes.

Para PostgreSQL:

  • pgBackRest como herramienta de respaldo principal con dos repositorios (S3 + Azure Blob)
  • Archivado WAL continuo en ambos repositorios
  • Copia de seguridad completa semanal + diferencial diario (a través de K8s CronJob)
  • Instantáneas del volumen Longhorn cada 4 horas para una reversión rápida
  • Verificación de restauración automatizada todos los miércoles
  • Monitoreo
  • Prometheus con alertas sobre antigüedad, falla y almacenamiento de la copia de seguridad

Para MySQL:

  • Percona XtraBackup para copias de seguridad físicas transmitidas a S3
  • Envío continuo de registros binarios a almacenamiento separado
  • Semanal completo + incremental diario (a través de K8s CronJob)
  • Diariomysqldumpde esquemas críticos para copias de seguridad lógicas portátiles
  • Instantáneas de volumen de Longhorn cada 4 horas
  • Verificación de restauración automatizada todos los jueves

Para el clúster Kubernetes:

  • Copia de seguridad diaria de Velero de espacios de nombres de bases de datos con instantáneas de PV
  • RKE2/k3s instantáneas etcd cada 6 horas en almacenamiento fuera del clúster
  • Repositorio
  • GitOps como fuente de verdad para todos los manifiestos

Para recuperación ante desastres:

  • Replicación entre regiones de S3 a la región DR
  • Azure GRS para copias de seguridad con redundancia geográfica
  • Exploración de DR mensual: reconstrucción completa del clúster a partir de copias de seguridad en la región de DR
  • Runbook documentado con árbol de decisión para cada escenario de falla

Conclusión

Las copias de seguridad de bases de datos son la última línea de defensa entre su negocio y una pérdida catastrófica de datos. Las estrategias descritas en este artículo (copias de seguridad físicas y lógicas, archivado continuo de WAL y binlog, almacenamiento en múltiples nubes con políticas de ciclo de vida, cifrado en cada capa, programación automatizada a través de Kubernetes CronJobs y verificación de restauración sistemática) representan el estado actual del arte para los entornos de producción MySQL y PostgreSQL.

La conclusión más importante es la siguiente:una estrategia de copia de seguridad es tan buena como su última prueba de restauración exitosa. Cada herramienta, script y patrón de arquitectura de este artículo existe para cumplir un propósito: garantizar que, cuando suceda lo peor, pueda recuperar sus datos, cumplir con sus compromisos de RTO y RPO y mantener su negocio en funcionamiento. Cree su sistema de respaldo, automatícelo, monitorícelo, pruébelo y luego pruébelo nuevamente. Tu yo futuro te lo agradecerá.