Workstation Logo
Producten
AI LabsOpenAI AgentsClaude AgentsGrok BotWorkstation CRM (WSL CRM)MarketingAlle Producten
AI-Oplossingen
AI-WerkstationsAI SME PackagesPrivé AIGPU-ClustersEdge AIEnterprise AI LabAI per Industrie
Diensten
PlatformmoderniseringDigitale engineeringDatafundamenten & AIAutonome operatiesAI-adviesDevOps-automatiseringCybersecuritySoftwareontwikkelingAgentontwikkelingMLOps-opzet
Over Ons
PartnersKlantverhalen
Artikelen
Documentatie
WSL ProxyRing PromoterWSL VaultJobshoutSysOps 24/7
Blog
ContactLogin
Workstation

AI-werkstations, AI multi-agent software, GPU-infrastructuur en intelligente agentoplossingen voor moderne bedrijven.

Contact

AI-oplossingen

AI-WerkstationsAI SME PackagesPrivé AIGPU-ClustersEdge AIEnterprise AI LabAI per Industrie

Producten

Alle ProductenWSL CRM & ERPMarketingOpenAI AgentsWSL ProxyRing PromoterWSL VaultJobshoutSysOps 24/7

Bedrijf

Over OnsWaarom WorkstationPartnersKlantverhalenPrijzenContact

Bronnen

ArtikelenDocumentatieBlogZoekenSitemap
UK-kantoor
77-79 Marlowes, Hemel Hempstead HP1 1LFRoute: neem afrit 20 van de M25, Outer LondonBedrijfsnummer: 11641870Ma - Vr: 9:00 - 18:00 GMT
+44 7515 356 146
België-kantoor
Workstation SRL, Rue Vanderkindere 34, 1180 Uccle, BrusselsBE 0751.518.683Ma - Vr: 9:00 - 18:00 CET
+32 492 45 67 46
India-kantoor
#159 Sector 9, Pocket 1, DDA Flats, 110077 Dwarka, New Delhi
+91 98881 98841

© 2026 Workstation AI. Alle rechten voorbehouden.

PrivacyCookiesServicevoorwaardenWebsite-sitemap

Loading blog...

Home / Blog
DatabaseDevOpsKubernetesBackend

Back-upstrategieën voor productiedatabases die echt werken: MySQL en PostgreSQL

Bewezen back-up- en herstelstrategieën voor MySQL en PostgreSQL in productie

Balinder Walia12 april 202629 min read

Het verliezen van productiegegevens is het soort incident dat een einde maakt aan carrières, bedrijven sluit en de voorpagina van Hacker News haalt om de verkeerde redenen. Toch beschouwen de meeste teams databaseback-ups als een bijzaak: een cronjob die iemand twee jaar geleden heeft opgezet en die sindsdien door niemand is geverifieerd. In dit artikel worden beproefde back-upstrategieën voor MySQL en PostgreSQL uiteengezet die zich hebben bewezen in productieomgevingen variërend van k3s-clusters met één knooppunt tot cloudimplementaties in meerdere regio's die dagelijks miljoenen transacties verwerken.

We behandelen het volledige spectrum: logische en fysieke back-upmethoden, point-in-time herstel, geautomatiseerde planning, cloudopslagdoelen, encryptie, verificatie, Kubernetes-native benaderingen en de rampenherstelplanning die alles met elkaar verbindt. Elke aanbeveling wordt geleverd met concrete configuratie en code die u kunt aanpassen aan uw omgeving.

Back-uptypen begrijpen

Voordat u in specifieke tools duikt, heeft u een duidelijk mentaal model nodig van de vier fundamentele back-upstrategieën en hoe deze interageren met hersteldoelstellingen. Elke strategie maakt een andere afweging tussen back-upsnelheid, opslagverbruik en hersteltijd.

Eenvolledige back-uplegt de volledige database op één enkel tijdstip vast. Het is het eenvoudigst om over na te denken en het snelst te herstellen, maar ook het duurst qua opslag en het langzaamst om te maken. Een incrementele back-up vanlegt alleen de gegevens vast die zijn gewijzigd sinds de laatste back-up van welk type dan ook. Het is snel te maken en compact qua opslag, maar bij herstel moet de volledige keten opnieuw worden afgespeeld: de laatste volledige back-up plus elke daaropvolgende incrementele back-up. Een differentiële back-up vanlegt alles vast wat er is veranderd sinds de laatste volledige back-up. Het neemt een middenweg in: groter dan een incrementeel, maar eenvoudiger te herstellen omdat je alleen het laatste volledige plus het nieuwste differentieel nodig hebt. Ten slotte legtcontinue archivering(WAL-archivering in PostgreSQL, binaire logstreaming in MySQL) elke individuele transactie vast terwijl deze plaatsvindt, waardoor herstel op een bepaald moment tussen back-ups mogelijk is.

Overzicht van de-back-upstrategie: volledig versus incrementeel versus differentieel versus continuDag 0Dag 1Dag 2Dag 3Dag 4Dag 5VolledigeIncr.verschil.WAL/BinlogVOLLEDIG (100%)VOLLEDIG (100%)+5%+3%+4%+2%+5%+8%+12%+14%Continue WAL / binaire logstream (elke transactie)HersteldoelVolledige back-upIncrementeelDifferentieelWAL/Binlog-streamHerstelpunt

De optimale strategie voor de meeste productiesystemen is een combinatie: wekelijkse volledige back-ups, dagelijkse incrementele of differentiële back-ups, en continue WAL/binlog-archivering. Dit geeft u zowel snel herstel van recente volledige back-ups als de mogelijkheid om te herstellen naar elk gewenst moment wanneer u dat nodig heeft.

MySQL Back-upmethoden

MySQL biedt verschillende back-uptools, elk geschikt voor verschillende databasegroottes en herstelvereisten. De juiste keuze hangt af van uw datavolume, acceptabele back-upperiode en RTO/RPO-doelen.

mysqldump — De universele logische back-up

mysqldumpproduceert SQL-instructies die het schema en de gegevens opnieuw creëren. Het werkt op elke MySQL-versie en opslagengine, waardoor het de universele fallback is. Het vergrendelt echter tabellen tijdens de dump (tenzij--single-transactionmet InnoDB wordt gebruikt), en de herstelsnelheid neemt aanzienlijk af voor databases groter dan 50-100 GB omdat het individuele INSERT-instructies opnieuw afspeelt.

# 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 — Parallelle logische back-up

mysqlpumpis een verbetering ten opzichte vanmysqldumpmet parallelle tabeldump en ingebouwde compressie. Het kan de back-uptijd voor databases met veel onafhankelijke tabellen aanzienlijk verkorten.

# 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 — Fysieke back-ups voor InnoDB

Voor databases groter dan 50 GB worden logische back-ups onpraktisch: zowel de back-upperiode als de hersteltijd groeien lineair met de gegevensgrootte. Percona XtraBackup maakt kopieën op fysiek niveau van InnoDB-gegevensbestanden zonder de database te vergrendelen, waardoor het geschikt is voor implementaties van meerdere 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

MySQL binair logboek — herstel op een bepaald tijdstip

MySQL binaire logs registreren elke gegevensmodificerende verklaring of rijwijziging. In combinatie met een volledige of fysieke back-up maken ze point-in-time herstel mogelijk tot elk moment nadat de back-up is gemaakt.

# 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 Back-upmethoden

Het back-up-ecosysteem van PostgreSQL is aantoonbaar rijker dan dat van MySQL, met tools van eerste partijen en een volwassen reeks gemeenschapsoplossingen die speciaal zijn gebouwd voor grootschalige productieomgevingen.

pg_dump en pg_dumpall — Logische back-ups

Net alsmysqldumpproduceertpg_dumplogische back-ups. Het aangepaste formaat (-Fc) is de aanbevolen standaard omdat het parallel herstel, selectief tabelherstel en ingebouwde compressie ondersteunt.

# 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 — Fysieke back-upbasis

pg_basebackupmaakt een fysieke kopie van de volledige PostgreSQL-gegevensmap. Het vormt de basis voor zowel zelfstandig herstel als het instellen van streamingreplicatie. Gecombineerd met WAL-archivering maakt het herstel op een bepaald tijdstip mogelijk.

# 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 — Back-upbeheer op ondernemingsniveau

pgBackRest is de gouden standaard voor PostgreSQL-back-upbeheer. Het ondersteunt volledige, incrementele en differentiële back-ups, parallelle back-up en herstel, encryptie, doelen met meerdere opslagplaatsen (lokale schijf, S3, GCS, Azure Blob) en geautomatiseerde WAL-archivering – allemaal via één enkele, samenhangende configuratie.

# /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 — Lichtgewicht WAL-archivering naar cloudopslag

WAL-G is een eenvoudiger alternatief voor pgBackRest dat zich richt op het streamen van WAL-segmenten en basisback-ups naar objectopslag in de cloud. Het is populair in containeromgevingen waar u één binair bestand met minimale configuratie wilt.

# 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 — Gecentraliseerde back-upserver

Barman (Backup and Recovery Manager) is ontworpen voor omgevingen waar een speciale back-upserver back-ups voor meerdere PostgreSQL-instanties beheert. Het ondersteunt zowel rsync/SSH- als streaming-replicatieprotocollen voor back-uptransport.

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

Point-in-Time-herstel (PITR)

Point-in-time herstel is de belangrijkste mogelijkheid in uw back-uptoolkit. Hiermee kunt u een database herstellen naar de exacte staat waarin deze zich op een bepaald moment bevond: niet alleen op het moment dat er back-ups werden gemaakt, maar elke seconde tussen back-ups. Dit is van cruciaal belang voor herstel na het per ongeluk verwijderen van gegevens, applicatiefouten die gegevens beschadigen en beveiligingsincidenten waarbij u het exacte moment van de inbreuk moet identificeren.

Point-in-Time Recovery (PITR) tijdlijn00:00Zon06:0012:0018:0000:00MaVolledige back-uppg_basebackup@ 00:00WAL / binaire logsegmenten (continu)✖DROPTAFEL@ 16:42:31Hersteldoel@ 16:42:301. Herstel de volledige2. Speel WAL opnieuw af omte targeten3. DB hersteld!PITR = Herstel laatste volledige back-up + Speel WAL/binlog-segmenten opnieuw af tot 1 seconde vóór de rampHerstelgranulariteit: per transactie (PostgreSQL WAL) of per seconde (MySQL binlog)

PITR voor PostgreSQL

PostgreSQL PITR werkt door een basisback-up te herstellen en WAL-segmenten opnieuw af te spelen tot aan de doeltijdstempel. Met pgBackRest is het hele proces één enkele opdracht.

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

MySQL PITR combineert fysiek XtraBackup-herstel met herhaling van binaire logbestanden.

# 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

Multi-Cloud back-uparchitectuur

Productieback-upstrategieën moeten rekening houden met het falen van een enkele cloudprovider of regio. Als u back-ups uitsluitend opslaat in hetzelfde cloudaccount en in dezelfde regio als uw productiedatabase, betekent dit dat een inbreuk op één account, een factureringsprobleem of een regionale storing zowel uw gegevens als uw back-ups tegelijkertijd kan uitschakelen. Een robuuste architectuur verzendt back-ups naar ten minste twee onafhankelijke opslagdoelen met replicatie tussen regio's.

Multi-Cloud back-uparchitectuurPostgreSQLPrimair + Replica'sMySQLPrimair + Replica's-coderingslaagAES-256-CBCTLS onderwegSSE-S3 / SSE-KMSin rustVersleuteling aan de clientzijde vanvia pgBackRest/ WAL-GAWS S3eu-west-1 (primair)Levenscyclus: IA → GletsjerAzure BlobWest-Europa (primair)OnveranderlijkheidsbeleidGoogle Cloudopslageuropa-west1 (primair)Nearline → ColdlineS3 Cross-regionaleus-oost-1 (DR)Azure GRSNoord-Europa (DR)GCS Multi-regioEU multi-regio (DR)Back-upbewaking &waarschuwenPrometheus-statistieken • Grafana-dashboards • PagerDuty / Slack-waarschuwingen bij back-upfouten of leeftijdsdrempelOnonderbroken pijlen = back-upstroomGestippelde pijlen = replicatie tussen regio'sStippellijn = encryptiegrens

Cloud Storage-configuratie met levenscyclusbeleid

# 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

Back-upcodering en beveiliging

-back-ups zijn een waardevol doelwit voor aanvallers. Een gestolen, niet-versleutelde back-up geeft een aanvaller een volledige kopie van uw productiegegevens zonder dat u uw actieve systemen hoeft te hacken. Elke back-up, zowel onderweg als in rust, moet worden gecodeerd.

Encryptie tijdens verzendingbetekent het gebruik van TLS voor alle verbindingen tussen de databaseserver en de back-upbestemming. Zowel pgBackRest als XtraBackup streamen via gecodeerde kanalen indien geconfigureerd met TLS. Bij verzending naar S3, Azure Blob of GCS gebruiken de client-SDK's standaard HTTPS.

Encryptie in rustheeft twee lagen. Encryptie aan de serverzijde (SSE) codeert gegevens nadat deze bij het opslagdoel zijn aangekomen: S3 SSE-KMS, Azure Storage Service Encryption of GCS-standaardcodering. Encryptie aan de clientzijde codeert gegevens voordat deze de databaseserver verlaten, waardoor de cloudprovider nooit platte tekstgegevens ziet. pgBackRest en WAL-G ondersteunen beide native versleuteling aan de clientzijde.

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

Bewaar encryptiesleutels afzonderlijk van de back-ups zelf. Een geheimenmanager zoals HashiCorp Vault, AWS Secrets Manager of Azure Key Vault is de aanbevolen aanpak. Als u de sleutel naast de back-up bewaart, heeft een aanvaller die toegang krijgt tot uw back-upopslag alles wat hij nodig heeft.

Geautomatiseerde back-upplanning

Handmatige back-ups zijn geen back-ups; het zijn ambities. Back-upschema's moeten worden geautomatiseerd, bewaakt en gewaarschuwd bij storingen.

Systeemcron voor Bare Metal en VM's

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

In Kubernetes-omgevingen vervangen CronJobs de systeemcron. Ze bieden ingebouwde logica voor opnieuw proberen, gelijktijdigheidscontrole en integratie met de RBAC en het geheimbeheer van het cluster.

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-native back-up benadert

Het uitvoeren van databases in Kubernetes introduceert een nieuwe dimensie in de back-upstrategie. Naast databaseback-ups op applicatieniveau moet u ook rekening houden met back-ups op clusterniveau (etcd), persistente volumemomentopnamen en door de operator beheerde back-ups.

Kubernetes Back-uppijplijnKubernetes-cluster (k3s / RKE2)CronJob-schema: 0 1 * * *Back-uppodpgBackRest /XtraBackup-containerPostgreSQL-podStatefulSet-replica 0PVC: pg-gegevensMySQL PodStatefulSet-replica 0PVC: mysql-dataLonghorn CSIPV-snapshots + replica'sVolumeSnapshot CRDVeleroBack-up op clusterniveauetcd + naamruimten + PV'sObjectopslagS3 / GCS / Azure Blob / MinIOgecodeerd en versieLevenscyclus-tiering ingeschakeldDB-back-ups + WALVeleroLonghorn S3 doelPrometheus + GrafanaBack-uptaakstatistieken + waarschuwingenCronJob succes/mislukkingspercentageHerstelpad1. Velero herstelt (cluster)2. pgBackRest/XtraBackup (gegevens)3. Longhorn-snapshot terugdraaienPlannerBack-upagentPostgreSQLMySQLVeleroLanghoornObjectopslag

Velero voor back-up op clusterniveau

Velero maakt een back-up van Kubernetes-bronnen (implementaties, services, configuratiekaarten, geheimen) en permanente volumes. Het is geen vervanging voor databaseback-ups op applicatieniveau; het legt een crash-consistente momentopname van PV's vast, die mogelijk niet transactioneel consistent is voor databases. Gebruik Velero voor clusterherstel en tools op applicatieniveau (pgBackRest, XtraBackup) voor databaseherstel.

# 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-snapshots op k3s

k3s-implementaties gebruiken gewoonlijk Longhorn als hun CSI-opslagprovider. Longhorn biedt snapshots op volumeniveau en de mogelijkheid om snapshots te repliceren naar S3-compatibele objectopslag. Combineer voor databases Longhorn-snapshots met back-ups op applicatieniveau voor diepgaande verdediging.

# 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

Door operator beheerde back-ups

Database-operators zoals CloudNativePG (voor PostgreSQL) en Percona Operator (voor MySQL) integreren back-upbeheer rechtstreeks in de databaselevenscyclus. De operator regelt de planning, WAL-archivering en retentie automatisch via aangepaste bronnen.

# 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

Cloudproviderspecifieke strategieën

AWS — RDS en Aurora

AWS RDS biedt geautomatiseerde dagelijkse snapshots met configureerbare retentie (tot 35 dagen) en continue back-up via archivering van transactielogboeken voor herstel op een bepaald tijdstip. Aurora voegt Backtrack toe, waarmee het cluster naar elk punt binnen het backtrack-venster kan worden teruggespoeld zonder dat herstel nodig is. Het keert eenvoudigweg de interne status van de database om.

# 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 — Flexibele server

Azure-database voor PostgreSQL en MySQL flexibele server omvat automatische back-ups met lokaal redundante of geo-redundante opslag. Geo-redundante back-up maakt herstel over meerdere regio's mogelijk voor noodherstel.

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

Cloud SQL biedt automatische back-ups en kant-en-klaar herstel op een bepaald tijdstip. Voor zelfbeheerde databases op GCE of GKE biedt GCS met nearline- en coldline-opslagklassen kosteneffectieve back-upopslag voor de lange termijn.

# 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

Back-upverificatie en hersteltesten

Een back-up die nog nooit is getest, is geen back-up; het is hoop. Geautomatiseerde hersteltests moeten volgens een regelmatig schema worden uitgevoerd, idealiter wekelijks, in een geïsoleerde omgeving. De test moet niet alleen valideren dat het herstel zonder fouten wordt voltooid, maar ook dat de herstelde gegevens consistent zijn en dat de applicatie verbinding kan maken en er query's op kan uitvoeren.

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

Planning voor noodherstel: RTO en RPO

Elke back-upstrategie moet worden ontworpen rond twee meetgegevens:Recovery Time Objective (RTO)– hoe lang u het zich kunt veroorloven om offline te zijn – enRecovery Point Objective (RPO)– hoeveel gegevens u zich kunt veroorloven te verliezen. Deze cijfers bepalen elke beslissing over de back-upfrequentie, -methode en -architectuur.

ScenarioRTORPOStrategie
E-commerce afrekenen< 5 min0 (geen gegevensverlies)Synchrone replicatie + continue WAL-archivering + hot standby failover
SaaS-toepassing< 30 min< 1 min.Streamingreplicatie + WAL-G continue archivering + geautomatiseerde failover
Intern gereedschap< 4 uur< 1 uurDagelijks verschil + uurlijks + WAL-archivering
Analyse/datawarehouse< 24 uur< 24 uurDagelijkse volledige back-up naar cloudopslag
Ontwikkelaar / staging< 48 uur< 1 weekWekelijkse volledige back-up

Voor nul-RPO hebt u synchrone replicatie naar ten minste één standby-server nodig. Dit voegt latentie toe aan elke schrijftransactie, maar garandeert dat geen enkele vastgelegde transactie verloren gaat. De meeste productiesystemen accepteren een RPO van bijna nul (seconden potentieel verlies) door gebruik te maken van asynchrone streaming-replicatie met continue WAL/binlog-archivering, waardoor de schrijflatentie wordt vermeden.

Runbook-sjabloon voor noodherstel

# 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

Back-upbewaking en waarschuwingen

Back-upsystemen falen stil. De database blijft draaien, de applicatie blijft verkeer verwerken, en niemand merkt dat back-ups drie weken geleden niet meer werken – totdat ze er een nodig hebben. Proactief monitoren is essentieel.

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

Veelvoorkomende fouten en antipatronen

Na het beheren van databaseback-ups in tientallen productieomgevingen zijn dit de fouten die de meeste schade veroorzaken.

1. Een back-up maken op dezelfde schijf als de database.Als de schijf defect raakt, verliest u zowel de database als de back-up. Schrijf back-ups altijd naar een afzonderlijk opslagdoel, idealiter buiten de host en buiten de regio.

2. Test nooit herstelbewerkingen.Een back-up die niet kan worden hersteld, is geen back-up. Plan wekelijks geautomatiseerde hersteltests en laat engineers elk kwartaal handmatige hersteloefeningen uitvoeren.

3. Volledig vertrouwend op replicatie als back-up.-replicatie is geen back-up. EenDROP TABLEop de primaire versie wordt onmiddellijk gerepliceerd naar alle replica's. Replicatie beschermt tegen hardwarefouten, niet tegen logische fouten.

4. Back-uptaken worden niet gecontroleerd.Cron-taken mislukken stil. Kubernetes CronJobs worden opgeschort. S3-inloggegevens verlopen. Elke back-uptaak ​​moet succes of falen melden aan een monitoringsysteem en waarschuwen als de meest recente succesvolle back-up ouder is dan uw RPO.

5. Encryptiesleutels opslaan naast back-ups.Als een aanvaller toegang krijgt tot uw back-upopslag, mag deze niet ook over de decoderingssleutel beschikken. Bewaar sleutels in een speciale geheimenmanager.

6. Geen retentiebeleid.Zonder levenscyclusbeleid groeit de back-upopslag grenzeloos. Definieer duidelijke bewaarperioden: 7 dagen voor WAL-segmenten, 30 dagen voor dagelijkse back-ups, 12 maanden voor maandelijkse back-ups, en automatiseer de verwijdering ervan.

7. Impact op back-upprestaties negeren.Het uitvoeren van een volledige back-up op een primaire database tijdens piekuren verslechtert de prestaties van de applicatie. Plan back-ups tijdens periodes met weinig verkeer, of maak een back-up vanaf een speciale replica.

8.mysqldumpgebruiken voor grote databases zonder--single-transaction.Zonder deze vlag vergrendeltmysqldumptabellen, waardoor schrijfbewerkingen worden geblokkeerd voor de duur van de dump. Voor grote databases kan dit minuten of uren downtime betekenen.

9. Vergeten een back-up te maken van de databaseconfiguratie.Gegevens herstellen is slechts het halve werk. Als upostgresql.conf,pg_hba.conf,my.cnf, replicatie-instellingen en gebruikersrechten verliest, kunt u de database niet terugbrengen naar een bruikbare staat. Neem configuratiebestanden op in uw back-upproces.

10. Het niet documenteren van de herstelprocedure.Tijdens een storing is het mogelijk dat de persoon die de database herstelt, niet de persoon is die de back-ups heeft gemaakt. Een geschreven, getest runbook is van cruciaal belang.

Kostenoptimalisatie voor back-upopslag

De kosten voor back-upopslag kunnen snel stijgen, vooral als er regelmatig volledige back-ups van grote databases worden gemaakt. Deze strategieën houden de kosten onder controle zonder de herstelbaarheid in gevaar te brengen.

Gebruik incrementele/differentiële back-ups.Een wekelijkse volledige plus dagelijkse differentiëlen gebruiken een fractie van de opslag vergeleken met dagelijkse volledige back-ups. De delta-herstelmogelijkheid van pgBackRest betekent dat incrementele back-ups bijna net zo snel worden hersteld als volledige back-ups.

Compressie inschakelen.Moderne compressie-algoritmen zoals zstd bieden uitstekende compressieverhoudingen (5:1 tot 10:1 voor typische databasegegevens) met minimale CPU-overhead. Zowel pgBackRest als XtraBackup ondersteunen zstd native.

Implementeer opslaglagen.Verplaats back-ups naar steeds goedkopere opslagniveaus naarmate ze ouder worden. Het eerder getoonde levenscyclusbeleid (S3 Standard → IA → Glacier, GCS Standard → Nearline → Coldline) kan de opslagkosten op de lange termijn met 70-90% verlagen.

Ontdubbel waar mogelijk.pgBackRest maakt gebruik van deduplicatie op blokniveau in zijn repository, waarbij alleen gewijzigde blokken in back-ups worden opgeslagen. Dit vermindert de opslagcapaciteit voor databases waarin de meerderheid van de gegevens statisch is, dramatisch.

Retentievensters van de juiste maat.Veel teams houden uit voorzichtigheid standaard back-ups voor altijd bij. Analyseer uw daadwerkelijke herstelpatronen en nalevingsvereisten en stel vervolgens de retentie in die daarbij past. Bij een bewaarvereiste van zeven jaar kan bij de meeste cloudproviders gebruik worden gemaakt van diepe archiefopslag voor minder dan $ 1/TB/maand.

# 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

Alles samen: een complete back-uparchitectuur

Hier is de aanbevolen back-uparchitectuur voor een productieomgeving met zowel MySQL als PostgreSQL, geïmplementeerd op Kubernetes met noodherstel in meerdere clouds.

Voor PostgreSQL:

  • pgBackRest als primaire back-uptool met twee repository's (S3 + Azure Blob)
  • Continue WAL-archivering naar beide repositories
  • Wekelijkse volledige back-up + dagelijks differentieel (via K8s CronJob)
  • Longhorn-volumesnapshots elke 4 uur voor snel terugdraaien van
  • Geautomatiseerde herstelverificatie elke woensdag
  • Prometheus-bewaking met waarschuwingen over back-upleeftijd, fouten en opslag

Voor MySQL:

  • Percona XtraBackup voor fysieke back-ups gestreamd naar S3
  • Continue verzending van binaire logbestanden naar aparte opslag
  • Wekelijks volledig + dagelijks incrementeel (via K8s CronJob)
  • Dagelijksemysqldumpvan kritische schema's voor draagbare logische backups
  • Longhorn-volumesnapshots elke 4 uur
  • Geautomatiseerde herstelverificatie elke donderdag

Voor het Kubernetes-cluster:

  • Velero dagelijkse back-up van databasenaamruimten met PV-snapshots
  • RKE2/k3s etcd snapshots elke 6 uur naar opslag buiten het cluster
  • GitOps-repository als bron van waarheid voor alle manifesten

Voor noodherstel:

  • S3 replicatie tussen regio's naar DR-regio
  • Azure GRS voor geo-redundante back-upkopieën
  • Maandelijkse DR-oefening: volledige clusteropbouw vanaf back-ups in DR-regio
  • Gedocumenteerd runbook met beslissingsboom voor elk foutscenario

Conclusie

Databaseback-ups vormen de laatste verdedigingslinie tussen uw bedrijf en catastrofaal gegevensverlies. De strategieën die in dit artikel worden beschreven – fysieke en logische back-ups, continue WAL- en binlog-archivering, multi-cloudopslag met levenscyclusbeleid, encryptie op elke laag, geautomatiseerde planning via Kubernetes CronJobs en systematische herstelverificatie – vertegenwoordigen de huidige stand van zaken voor productie-MySQL- en PostgreSQL-omgevingen.

De belangrijkste conclusie is dit:een back-upstrategie is slechts zo goed als zijn laatste succesvolle hersteltest. Alle tools, scripts en architectuurpatronen in dit artikel dienen één doel: ervoor zorgen dat wanneer het ergste gebeurt, u uw gegevens kunt herstellen, aan uw RTO- en RPO-verplichtingen kunt voldoen en uw bedrijf draaiende kunt houden. Bouw uw back-upsysteem, automatiseer het, monitor het, test het en test het vervolgens opnieuw. Je toekomstige zelf zal je dankbaar zijn.