Záloha databází: MySQL, PostgreSQL a MongoDB

Databáze jsou srdcem většiny aplikací. Jejich ztráta znamená ztrátu klíčových business dat. Naučte se správně zálohovat MySQL, PostgreSQL i MongoDB s podporou point-in-time recovery.

Proč je záloha databází specifická?

Zálohování databáze není totéž jako kopírování souborů. Databáze jsou živé systémy, které neustále zapisují data do datových souborů, transakčních logů a cache. Prostá kopie souborů databáze za běhu vede téměř jistě k poškozené, nekonzistentní záloze.

Správná záloha databáze musí zajistit:

  • Konzistenci -- všechny tabulky a relace musí být v konzistentním stavu
  • Úplnost -- žádná rozpracovaná transakce nesmí být zachycena částečně
  • Obnovitelnost -- záloha musí být úspěšně obnovitelná (nestačí ji vytvořit, musíte ji ověřit)
  • Minimální dopad na provoz -- záloha by neměla výrazně zpomalovat produkční databázi

Logické vs. fyzické zálohy

Existují dva fundamentálně odlišné přístupy k zálohování databází:

Logická záloha

Exportuje data ve formátu SQL příkazů (CREATE TABLE, INSERT) nebo jiném textovém formátu. Nástroje: mysqldump, pg_dump, mongodump.

    Výhody

  • Přenositelnost mezi verzemi a platformami
  • Možnost selektivní obnovy (jedna tabulka)
  • Čitelný formát (SQL text)
  • Nezávislost na úložišti

    Nevýhody

  • Pomalé pro velké databáze (GB-TB)
  • Vyšší zátěž na databázový server
  • Obnova trvá dlouho (replayování SQL)
  • Záloha může být nekonzistentní bez zámků

Fyzická záloha

Kopíruje datové soubory databáze na binární úrovni. Nástroje: xtrabackup (MySQL), pg_basebackup (PostgreSQL), LVM snapshot, filesystem snapshot.

    Výhody

  • Velmi rychlá záloha i obnova
  • Minimální zátěž na server
  • Konzistentní bez zámků (u moderních nástrojů)
  • Podpora inkrementálních záloh

    Nevýhody

  • Závislost na verzi a platformě databáze
  • Nelze selektivně obnovit jednu tabulku
  • Větší velikost zálohy
  • Složitější správa

Hot vs. cold zálohy

Hot backup (online záloha) probíhá za běhu databáze, bez nutnosti ji zastavit. Uživatelé mohou dále číst i zapisovat. Moderní nástroje (xtrabackup, pg_basebackup) toto podporují.

Cold backup (offline záloha) vyžaduje zastavení databáze. Zaručuje 100% konzistenci, ale způsobuje výpadek. V produkčním prostředí je obvykle nepřijatelná.

Doporučení Pro produkční databáze vždy používejte hot backup nástroje. Cold backup je přijatelný pouze pro vývojové a testovací prostředí nebo při plánovaných maintenance oknech.

MySQL / MariaDB

mysqldump

Základní logický zálohovací nástroj dodávaný s MySQL. Exportuje data jako SQL příkazy:

# Záloha jedné databáze
mysqldump -u root -p --single-transaction --routines --triggers \
  --databases mydb > /backup/mydb_$(date +%F_%H%M).sql

# Záloha všech databází
mysqldump -u root -p --single-transaction --all-databases \
  --routines --triggers --events > /backup/all_$(date +%F).sql

# Záloha s kompresí
mysqldump -u root -p --single-transaction --databases mydb | \
  gzip > /backup/mydb_$(date +%F).sql.gz

# Obnova
mysql -u root -p mydb < /backup/mydb_2025-01-15_0200.sql

# Obnova z komprimované zálohy
gunzip < /backup/mydb_2025-01-15.sql.gz | mysql -u root -p mydb

Klíčové parametry:

  • --single-transaction -- konzistentní záloha InnoDB tabulek bez zámků (používá MVCC snapshot)
  • --routines -- zahrne uložené procedury a funkce
  • --triggers -- zahrne triggery
  • --events -- zahrne naplánované události
  • --master-data=2 -- zapíše pozici v binary logu (pro replikaci a PITR)
Pozor: mysqldump a MyISAM tabulky Parametr --single-transaction funguje pouze s InnoDB enginem. Pro MyISAM tabulky je nutné použít --lock-all-tables, což zablokuje zápisy po dobu zálohy. Pokud to je možné, migrujte MyISAM tabulky na InnoDB.

mysqlpump

Vylepšená verze mysqldump dostupná od MySQL 5.7. Hlavní výhoda je paralelní export -- může využívat více vláken pro rychlejší zálohu:

# Paralelní záloha s 4 vlákny
mysqlpump -u root -p --default-parallelism=4 \
  --databases mydb > /backup/mydb_pump_$(date +%F).sql

Percona XtraBackup

XtraBackup je nejpoužívanější nástroj pro fyzické zálohy MySQL/MariaDB. Vytváří hot backup bez zámků a podporuje inkrementální zálohy:

# Full backup
xtrabackup --backup --target-dir=/backup/full_$(date +%F) \
  --user=root --password=heslo

# Inkrementální backup (na základě předchozí full zálohy)
xtrabackup --backup --target-dir=/backup/inc_$(date +%F) \
  --incremental-basedir=/backup/full_2025-01-15 \
  --user=root --password=heslo

# Příprava zálohy pro obnovu (apply log)
xtrabackup --prepare --target-dir=/backup/full_2025-01-15

# Příprava s inkrementální zálohou
xtrabackup --prepare --target-dir=/backup/full_2025-01-15 \
  --incremental-dir=/backup/inc_2025-01-16

# Obnova (databáze musí být zastavena)
systemctl stop mysql
xtrabackup --copy-back --target-dir=/backup/full_2025-01-15
chown -R mysql:mysql /var/lib/mysql
systemctl start mysql

Point-in-Time Recovery (MySQL)

PITR umožňuje obnovit databázi k libovolnému bodu v čase. Vyžaduje:

  1. Povolenou binární log replikaci (log-bin v my.cnf)
  2. Pravidelnou full zálohu (mysqldump s --master-data nebo xtrabackup)
  3. Uchování binary logů mezi zálohami
# Konfigurace v my.cnf
[mysqld]
log-bin = /var/log/mysql/mysql-bin
binlog_format = ROW
expire_logs_days = 14
server-id = 1

# Obnova k bodu v čase
# 1. Obnovte poslední full backup
# 2. Aplikujte binary logy od zálohy do požadovaného času
mysqlbinlog --start-position=4 --stop-datetime="2025-01-16 14:30:00" \
  /var/log/mysql/mysql-bin.000042 \
  /var/log/mysql/mysql-bin.000043 | mysql -u root -p

PostgreSQL

pg_dump

Logický zálohovací nástroj PostgreSQL. Na rozdíl od mysqldump vytváří konzistentní snapshot bez zámků standardně (díky MVCC):

# Záloha jedné databáze (SQL formát)
pg_dump -U postgres -d mydb -F p -f /backup/mydb_$(date +%F).sql

# Záloha v custom formátu (komprimovaný, paralelní obnova)
pg_dump -U postgres -d mydb -F c -f /backup/mydb_$(date +%F).dump

# Záloha v directory formátu (paralelní záloha i obnova)
pg_dump -U postgres -d mydb -F d -j 4 -f /backup/mydb_$(date +%F)/

# Záloha všech databází
pg_dumpall -U postgres -f /backup/all_$(date +%F).sql

# Obnova z custom formátu
pg_restore -U postgres -d mydb -j 4 /backup/mydb_2025-01-15.dump

# Obnova s vytvořením databáze
pg_restore -U postgres -C -d postgres /backup/mydb_2025-01-15.dump

Klíčové formáty:

  • -F p (plain) -- čistý SQL text, obnovitelný přes psql
  • -F c (custom) -- komprimovaný binární formát, podpora selektivní a paralelní obnovy přes pg_restore
  • -F d (directory) -- každá tabulka v samostatném souboru, podpora paralelní zálohy (-j)
  • -F t (tar) -- tar archiv, kompatibilní s pg_restore

pg_basebackup

Fyzická záloha celého PostgreSQL clusteru. Nezbytná pro nastavení WAL archivace a PITR:

# Fyzická záloha celého clusteru
pg_basebackup -U replicator -D /backup/pg_base_$(date +%F) \
  -Ft -z -P -R --checkpoint=fast

# Parametry:
# -Ft    -- tar formát
# -z     -- gzip komprese
# -P     -- progress reporting
# -R     -- vytvoří standby.signal a recovery konfiguraci
# --checkpoint=fast  -- neprodlužuje zálohu čekáním na checkpoint

WAL archivace a PITR (PostgreSQL)

WAL (Write-Ahead Log) je transakční log PostgreSQL. Archivací WAL souborů v kombinaci s pg_basebackup získáte možnost PITR:

# Konfigurace v postgresql.conf
wal_level = replica
archive_mode = on
archive_command = 'cp %p /backup/wal_archive/%f'
# nebo pro vzdálené úložiště:
# archive_command = 'aws s3 cp %p s3://pg-wal-archive/%f'

# Obnova k bodu v čase
# 1. Zastavte PostgreSQL
# 2. Obnovte base backup do datového adresáře
# 3. Vytvořte recovery konfiguraci

# V postgresql.conf (PostgreSQL 12+):
restore_command = 'cp /backup/wal_archive/%f %p'
recovery_target_time = '2025-01-16 14:30:00'
recovery_target_action = 'promote'

# 4. Vytvořte soubor recovery.signal
touch /var/lib/postgresql/16/main/recovery.signal

# 5. Spusťte PostgreSQL -- automaticky provede PITR
systemctl start postgresql
pgBackRest -- profesionální zálohovací nástroj Pro produkční PostgreSQL doporučujeme pgBackRest. Nabízí paralelní zálohy, inkrementální a diferenciální zálohy, integrovanou WAL archivaci, kompres (LZ4, ZSTD), šifrování a automatickou retenci.
# pgBackRest konfigurace (/etc/pgbackrest/pgbackrest.conf)
[mydb]
pg1-path=/var/lib/postgresql/16/main

[global]
repo1-path=/backup/pgbackrest
repo1-retention-full=4
repo1-retention-diff=7
compress-type=zst

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

# Diferenciální backup
pgbackrest --stanza=mydb backup --type=diff

# Inkrementální backup
pgbackrest --stanza=mydb backup --type=incr

# Obnova k bodu v čase
pgbackrest --stanza=mydb restore --type=time \
  --target="2025-01-16 14:30:00+01"

# Ověření zálohy
pgbackrest --stanza=mydb verify

MongoDB

MongoDB nabízí několik přístupů k zálohování:

mongodump / mongorestore

# Záloha celé instance
mongodump --uri="mongodb://localhost:27017" --out=/backup/mongo_$(date +%F)

# Záloha jedné databáze
mongodump --db=mydb --out=/backup/mongo_$(date +%F)

# Záloha s kompresí
mongodump --db=mydb --gzip --out=/backup/mongo_$(date +%F)

# Obnova
mongorestore --db=mydb /backup/mongo_2025-01-15/mydb/

# Obnova s drop (přepíše existující data)
mongorestore --db=mydb --drop /backup/mongo_2025-01-15/mydb/

MongoDB Atlas Backup

Pokud používáte MongoDB Atlas (managed cloud), máte k dispozici automatické continuous backups s možností PITR. Atlas pořizuje snapshoty každých 6 hodin a uchovává oplog pro PITR v rozmezí posledních 24 hodin (nebo déle u vyšších plánů).

Filesystem snapshoty pro MongoDB

Pro velké MongoDB instance je efektivnější použít filesystem snapshot (LVM, ZFS, EBS snapshot) místo mongodump:

# MongoDB s WiredTiger enginem -- filesystem snapshot je konzistentní
# 1. Zamkněte databázi
mongosh --eval "db.fsyncLock()"

# 2. Vytvořte snapshot (příklad pro LVM)
lvcreate -L 10G -s -n mongo_snap /dev/vg_data/lv_mongo

# 3. Odemkněte databázi
mongosh --eval "db.fsyncUnlock()"

# 4. Záloha ze snapshotu
mount /dev/vg_data/mongo_snap /mnt/snapshot
cp -a /mnt/snapshot/mongodb/ /backup/mongo_snap_$(date +%F)/
umount /mnt/snapshot
lvremove /dev/vg_data/mongo_snap

Plánování a automatizace záloh

Zálohy databází by měly být plně automatizované. Nikdy se nespoléhejte na manuální spouštění.

# Cron job pro denní zálohu MySQL (02:00)
0 2 * * * /usr/local/bin/backup-mysql.sh >> /var/log/backup-mysql.log 2>&1

# Příklad backup skriptu
#!/bin/bash
set -euo pipefail

BACKUP_DIR="/backup/mysql"
DATE=$(date +%F_%H%M)
RETENTION_DAYS=30

# Vytvoření zálohy
mysqldump -u backup_user --single-transaction \
  --all-databases --routines --triggers --events | \
  gzip > "${BACKUP_DIR}/all_${DATE}.sql.gz"

# Ověření (kontrola, že soubor není prázdný a je validní gzip)
if ! gzip -t "${BACKUP_DIR}/all_${DATE}.sql.gz" 2>/dev/null; then
    echo "ERROR: Záloha je poškozená!" >&2
    exit 1
fi

# Smazání starých záloh
find "${BACKUP_DIR}" -name "*.sql.gz" -mtime +${RETENTION_DAYS} -delete

echo "OK: Záloha ${DATE} dokončena, velikost: $(du -h ${BACKUP_DIR}/all_${DATE}.sql.gz | cut -f1)"

Ověřování záloh

Záloha, kterou jste netestovali, je jen přání. Automatizujte ověřování:

  • Kontrola integrity -- ověřte, že soubor zálohy není poškozený (gzip -t, pg_restore --list)
  • Testovací obnova -- pravidelně obnovujte zálohu do testovací instance
  • Kontrola dat -- po obnově ověřte počty záznamů, kontrolní součty kritických tabulek
  • Monitoring -- nastavte alerty na neúspěšné zálohy a na zálohy, které se neuskutečnily
# Automatické ověření zálohy PostgreSQL
# Obnovení do dočasné databáze a kontrola
createdb -U postgres test_restore
pg_restore -U postgres -d test_restore /backup/mydb_2025-01-15.dump

# Kontrola počtu záznamů
psql -U postgres -d test_restore -c "SELECT count(*) FROM users;"
psql -U postgres -d test_restore -c "SELECT count(*) FROM orders;"

# Úklid
dropdb -U postgres test_restore
Zlaté pravidlo zálohování databází Zálohu, kterou jste nikdy úspěšně neobnovili, nemůžete považovat za zálohu. Naplánujte si pravidelné testovací obnovy -- minimálně jednou měsíčně. Ideálně automatizujte celý proces včetně porovnání dat.

Doporučené postupy

  1. Kombinujte logické a fyzické zálohy -- logické pro flexibilitu, fyzické pro rychlost
  2. Nastavte PITR -- binary logy (MySQL) nebo WAL archivace (PostgreSQL) umožňují obnovu k libovolnému bodu v čase
  3. Zálohujte na oddělené úložiště -- zálohy by neměly být na stejném disku jako databáze
  4. Šifrujte zálohy -- databáze obsahují citlivá data, zálohy musí být chráněny
  5. Dokumentujte postup obnovy -- v krizi nemáte čas experimentovat
  6. Monitorujte velikost a trvání záloh -- neočekávané změny mohou indikovat problém
  7. Oddělte zálohovací přístupy -- zálohovací uživatel by měl mít minimální práva (SELECT, RELOAD, LOCK TABLES, REPLICATION CLIENT)
  8. Testujte obnovu pravidelně -- automatizovaná měsíční obnova do testovací instance

Závěr

Záloha databází vyžaduje specifický přístup odlišný od zálohování souborů. Klíčem je porozumět rozdílu mezi logickými a fyzickými zálohami, nastavit PITR pro možnost obnovy k libovolnému bodu v čase a pravidelně ověřovat obnovitelnost záloh. Pro MySQL doporučujeme kombinaci mysqldump (malé databáze) a Percona XtraBackup (velké databáze). Pro PostgreSQL je ideální kombinace pg_dump, pg_basebackup a WAL archivace -- nebo komplexní řešení pgBackRest.