Zálohy databází selhávají jinak než zálohy souborů. Napůl zkopírovaný soubor světa je zjevně rozbitý - nenačte se a víš to do minuty. Napůl konzistentní dump databáze se obnoví čistě a tiše je špatně: tabulka orders má řádky, které tabulka order_items nemá, cizí klíč ukazuje na nic a aplikace funguje, dokud někdo neotevře tu jednu stránku, která sahá na obojí. Nástroje, jak se tomu vyhnout, existují a stojí tě jeden přepínač.
Stručně: pro PostgreSQL používej pg_dump a pro MongoDB mongodump, nikdy ne kopii souborů běžícího datového adresáře, dump zapisuj někam mimo stroj a obnovuj ho pravidelně do pomocné databáze, abys věděl, že funguje. Všechno níže je detail, včetně přepínačů, na kterých záleží, věcí, které dumpy nechávají za sebou, a toho, co dělat, když si ztrátu hodiny zápisů dovolit nemůžeš.
Proč kopie souborů běžící databáze není záloha#
Databáze je sada souborů, které dávají smysl jen dohromady v jednom okamžiku. Za běhu se zapisují stránky, write-ahead log předbíhá datové soubory a něco z toho, co aplikace považuje za potvrzené, je pořád v paměti. tar procházející ten adresář vezme soubor A ve 03:00:01 a soubor Z ve 03:04:12 a výsledkem je sada souborů, které nikdy společně neexistovaly.
U PostgreSQL je obnova z takové kopie někdy možná a vždy ošklivá. U MongoDB s enginem WiredTiger je to obvykle prostě poškozený datový adresář. „Zálohoval jsem složku“ je nejčastější způsob, jak se záloha ukáže jako žádná záloha.
Existují tři legitimní přístupy a odpovídají na různé otázky:
| Metoda | Co ti dává | Cena |
|---|---|---|
Logický dump (pg_dump, mongodump) | Přenositelná kopie čitelná člověkem; obnova jedné tabulky | Při velké databázi pomalá obnova; snímek, ne průběžná záloha |
Fyzická záloha (pg_basebackup, snímek souborového systému při zastavené databázi) | Rychlá obnova celého clusteru | Vázaná na stejnou hlavní verzi a platformu; všechno nebo nic |
| Průběžné archivování (WAL shipping, oplog replica setu) | Obnova na zvolenou sekundu | Potřebuje úložiště, které ovládáš, a skutečné nastavení |
Pro jednu nebo dvě databáze za herním serverem, botem nebo webovou aplikací jsou správnou odpovědí logické dumpy a zbytek tohoto článku z nich vychází. Průběžné archivování má vlastní sekci na konci, protože ve chvíli, kdy si nemůžeš dovolit ztratit hodinu zápisů, nepomůže nic jiného.
PostgreSQL: dump, kterému můžeš věřit#
pg_dump otevře jedinou transakci s izolací repeatable-read a přečte celou databázi z jednoho snímku. Všechno v souboru pochází ze stejného okamžiku, bez ohledu na to, jak dlouho dump trvá nebo co aplikace mezitím dělá. Za tuhle vlastnost platíš.
$ export PGPASSWORD=... # better: use ~/.pgpass, see below$ pg_dump --host=db.example.net --port=5432 --username=app \ --format=custom --no-owner --no-privileges \ --file=/backups/app-$(date +%F).dump app| Přepínač | Proč |
|---|---|
--format=custom (-Fc) | Komprimovaný a jediný formát, ze kterého umí pg_restore obnovovat výběrově |
--format=directory (-Fd) | Jediný formát, který podporuje paralelní dump pomocí -j |
--no-owner | Nevypisuje ALTER ... OWNER TO, což selže, když cíl má jiné role |
--no-privileges (-x) | Přeskočí GRANT/REVOKE; hodí se při obnově do pomocné databáze |
--schema-only / --data-only | Jen struktura nebo jen řádky, pro porovnání a částečné obnovy |
--table=orders (-t) | Jedna tabulka. Pozor, nesleduje závislosti |
--jobs=4 (-j) | Paralelní dump, jen formát directory |
Dvě věci, které pg_dump neobsahuje, a obě tě kousnou v den obnovy:
- Role, hesla a tablespaces. Jsou platné pro celý cluster, ne pro jednu databázi. Zálohuj je zvlášť pomocí
pg_dumpall --globals-only > globals.sqla ulož soubor vedle dumpu. Bez něj obnova na čerstvý server vyrobí databázi, v níž uživatel aplikace neexistuje. - Samotná rozšíření. Dump obsahuje
CREATE EXTENSION postgis;, ale ne PostGIS. Cílový server musí mít rozšíření už k dispozici, jinak se obnova na tomto místě zastaví.
Přihlašovací údaje nedávej na příkazový řádek - všechno, co tam napíšeš, vidí v seznamu procesů každý další uživatel na stroji. Použij raději soubor s hesly:
db.example.net:5432:app:app_user:the-passwordJedno pravidlo o verzích, které stojí za zapamatování: spouštěj binárky pg_dump a pg_restore z verze alespoň tak nové, jako je server, se kterým mluvíš. Starší pg_dump proti novějšímu serveru odmítne běžet a dump vytvořený novější hlavní verzí se do starší nenačte vždy. Při přechodu mezi hlavními verzemi dumpuj nástroji nové verze.
PostgreSQL: vrácení zpět#
Obnovuj do prázdné databáze, nikdy přes živou, kterou jsi předtím nezazálohoval.
$ createdb -h db.example.net -U app app_restore$ pg_restore --host=db.example.net --username=app --dbname=app_restore \ --no-owner --no-privileges --jobs=4 /backups/app-2026-09-21.dump--jobs je přepínač, který u čehokoli většího změní hodinu na patnáct minut; načítá tabulky a staví indexy paralelně a funguje s archivy custom nebo directory. Na tarifu s jedním nebo dvěma vCPU se nad -j 2 nedá mnoho získat, protože tě omezuje stejné škrcení jako všechno ostatní.
Užitečné varianty:
- Nahradit existující databázi na místě: přidej
--clean --if-exists. Přečti si to dvakrát, než to spustíš proti produkčnímu názvu. Objekty před znovuvytvořením zahazuje, a pokud v dumpu chybí tabulka, je teď pryč. - Obnovit jednu tabulku:
pg_restore -d app_restore -t orders app.dump. Indexy a omezení, která k ní patří, se automaticky nezahrnou, proto si nejdřív zkontrolujpg_restore -l app.dump- vypíše obsah archivu, který můžeš upravit a vrátit přes-Lpro přesnou výběrovou obnovu. - Prostý SQL dump (
-Fp, nebo cokoli vytvořenépg_dumpall) sepg_restorevůbec neobnovuje. Je to skript:psql -d app_restore -f app.sql. Přidej-v ON_ERROR_STOP=1, jinak poběží bez problémů dál i přes chybu a nic ti neřekne.
Varování o vlastnictví a komentářích u rozšíření očekávej i při čisté obnově; při použití --no-owner je to šum. Šum není nenulový návratový kód ani řádek obsahující ERROR:. Výstup přesměruj do souboru a přečti si ho.
MongoDB: mongodump a mongorestore#
Nástroje už nejsou součástí balíčku serveru - dodávají se jako MongoDB Database Tools a instalují se zvlášť. Ověř si to příkazem mongodump --version dřív, než je budeš potřebovat ve dvě ráno.
$ mongodump --uri="mongodb://app:PASSWORD@db.example.net:27017/?authSource=admin" \ --db=app --gzip --archive=/backups/app-$(date +%F).gz--archive zapisuje jeden proud místo stromu adresářů, což chceš, pokud se soubor bude nahrávat nebo posílat rourou jinam. --gzip ho komprimuje. authSource je databáze, ve které byl uživatel vytvořen, téměř vždy admin, a když ho zadáš špatně, vznikne selhání autentizace, které vypadá jako špatné heslo.
Důležitá je poznámka ke konzistenci. Na samostatném mongod čte mongodump kolekce jednu po druhé bez snímku, takže dump databáze, do které se zapisuje, nemá zaručenou konzistenci napříč kolekcemi. Na replica setu --oplog zaznamená operace, které proběhly během dumpu, aby je mongorestore --oplogReplay mohl přehrát do jednoho časového bodu:
$ mongodump --uri="mongodb://...@host:27017/?authSource=admin" \ --oplog --gzip --archive=/backups/full-$(date +%F).gzPokud jsi na samostatné instanci a na datech záleží, buď dumpuj v klidném okně, nebo přijmi, že konzistence napříč kolekcemi není zaručena, a navrhni aplikaci tak, aby na tom nezáleželo.
Obnova:
$ mongorestore --uri="mongodb://app:PASSWORD@db.example.net:27017/?authSource=admin" \ --gzip --archive=/backups/app-2026-09-21.gz \ --nsFrom='app.*' --nsTo='app_restore.*'Dvojice --nsFrom a --nsTo je v MongoDB ekvivalent obnovy do pomocné databáze: stejná data dorazí pod jiným názvem vedle produkce, kde můžeš spočítat dokumenty a nasměrovat na ně kopii aplikace. Další užitečné přepínače: --drop odstraní každou kolekci před obnovou (destruktivní, platí stejné varování jako u --clean výše), --nsInclude='app.orders' obnoví jedinou kolekci a --restoreDbUsersAndRoles vrátí uživatele a role, když obnovuješ databázi, která je měla.
Ověření u Mongo je jednořádkový příkaz v shellu, ne pocit:
db.getSiblingDB("app_restore").orders.countDocuments()db.getSiblingDB("app_restore").stats()Porovnej s produkcí. Pokud jsou čísla blízká, ale ne stejná, takhle vypadá nekonzistentní dump, a je to důvod, proč se starat o výše zmíněnou otázku replica setu. Postgres nebo MongoDB rozebírá širší volbu mezi oběma, pokud se ještě rozhoduješ.
Slot pro databázi, který přišel s tvým herním nebo aplikačním tarifem#
Herní tarif obsahuje jeden slot pro databázi a řady pro aplikace a web dva. Vytváří se v panelu s vygenerovaným hostem, uživatelem a heslem a spravují se přes phpMyAdmin s jednorázovým přihlašovacím tokenem, který vyprší po šedesáti sekundách. Pro zálohy použij jeho záložku Export: vyber celou databázi, zvol SQL a komprimaci.
Dvě omezení, než se na to spolehneš. Export přes prohlížeč je v pořádku do několika set megabajtů a nad to nepříjemný, protože se stahování generuje za běhu a přerušené spojení znamená začít znovu. Import má omezení tvrdší: velikost nahrávaného souboru, kterou rozhraní přijme. Dump, který se čistě exportuje, se může odmítnout importovat a obvyklým řešením je rozdělit ho nebo obnovit z shellu. Import a export ve phpMyAdmin prochází možnosti v tomto dialogu jednu po druhé.
Vyhrazená řada hostingu databází je jiná: PostgreSQL a MongoDB, heslo superuživatele generované pro každý server, dostupné přímo na hostu a portu tarifu. To znamená, že výše uvedené nástroje příkazové řádky proti ní fungují přesně tak, jak jsou napsané, což je hlavní praktický důvod, proč přesunout rostoucí databázi ze slotu na vlastní tarif.
Dostat dump pryč ze stroje#
Dump ležící na stejném úložišti jako databáze, kterou chrání, kryje jedno selhání: že sám zahodíš vlastní tabulku. Nekryje nic z disku, stroje nebo účtu. Je to stejný argument jako v zálohách, které se opravdu obnoví, a u databází platí o to víc, že dump je malý a nemáš žádnou výmluvu.
Vzor, který na panelu funguje, nechává oba systémy navázat na sebe:
- Plán zapíše dump do složky samotného serveru několik minut před úlohou zálohy.
- Úloha zálohy archivuje složku včetně dumpu a archiv se uloží mimo stroj, který chrání.
- Jednou týdně stáhneš jeden z těch archivů někam, co s tvým hostingem nesouvisí.
Na VDS nebo kdekoli, kde máš cron, totéž jedním řádkem a rotací:
0 4 * * * pg_dump -Fc -f /backups/app-$(date +\%F).dump app && \ find /backups -name 'app-*.dump' -mtime +14 -deleteVšimni si escapovaného % - bez escapování cron příkaz u prvního z nich ořízne, což je klasický důvod, proč úloha zálohy tiše nevytvoří nic. Zkontroluj, že soubor existuje a má rozumnou velikost, hned další ráno, ne za tři měsíce. Pořadí a časování těchto úloh na panelu popisují naplánované úlohy, které stojí za to mít.
Když ztráta hodiny není přijatelná#
Noční dumpy znamenají, že selhání ve 23:00 ztratí celý den. Pokud je to opravdu nepřijatelné - e-shop, účetní kniha, cokoli, kde jsou řádky peníze - potřebuješ průběžné archivování, které mění to, co musíš provozovat.
U PostgreSQL je to point-in-time recovery: nastav archive_mode = on a archive_command, který kopíruje každý dokončený segment write-ahead logu na bezpečné místo, pravidelně pořizuj základní zálohu přes pg_basebackup a při obnově vrať základní zálohu a nech server přehrát logy až k recovery_target_time, který zvolíš. Dostaneš libovolnou sekundu mezi základní zálohou a posledním archivovaným segmentem. Vyžaduje to také roli s atributem REPLICATION, místo na segmenty a dost disciplíny, abys všiml, když archivování přestane - selhávající archive_command zaplní datový adresář nedoručenými logy, dokud nedojde disk.
U MongoDB je ekvivalentem replica set plus pravidelné dumpy s --oplog a praktickou hranicí je, jak daleko dozadu sahá okno oplogu: pokud tvůj oplog drží šest hodin operací, můžeš obnovit na libovolný bod do šesti hodin od posledního dumpu a dál ne.
Obojí chce stroj, který ovládáš, ne slot. To je poctivý argument pro VDS: ne výkon, ale možnost spustit archivační příkaz a uložit jeho výstup, kam sám rozhodneš. Než to postavíš, ujisti se, že požadavek je skutečný, protože provozní cena trvá a noční dump, který je opravdu otestovaný, je lepší než nastavení PITR, které nikdo nevyzkoušel.
Důkaz, že obnova funguje#
Smyslem všech sekcí výše je soubor. Soubor není záloha, dokud se z něj znovu nestane databáze.
- Vytvoř prázdnou databázi vedle skutečné, nebo jmenný prostor s jiným názvem.
- Obnov do ní přesně tím příkazem, který bys použil při incidentu. Změř čas.
- Spočítej řádky ve třech nejdůležitějších tabulkách a porovnej s produkcí.
- Nasměruj na ni kopii aplikace, pokud to jde, a otevři stránku, která používá nejvíc joinů.
- Zahoď ji.
Dělej to jednou za čtvrtletí a máš zálohu. Přeskoč to a máš soubor. Celý postup, včetně toho, jak změřit čísla, která produkuje, a co se obvykle rozbije, najdeš v testování obnovy dřív, než ji potřebuješ. Pokud tvoje obnova zahrnuje schéma, které se od pořízení dumpu posunulo, přečti si i migrace bez odstávky, protože obnova starých dat pod novým kódem je samostatná kategorie špatných dnů.
FAQ#
Můžu databázové soubory prostě zkopírovat, když běží?
Ne. Soubory jsou konzistentní jen společně v jednom okamžiku a kopie pořizovaná několik minut zachytí několik okamžiků. Použij pg_dump nebo mongodump, nebo databázi před kopírováním adresáře zastav. Snímek zastavené databáze je naprosto dobrá záloha; kopie běžící není.
Jak často mám dumpovat?
Denně je minimum pro cokoli se skutečnými uživateli a hodinově je to levné u databáze do několika gigabajtů, protože komprimovaný dump malé databáze trvá sekundy. Přizpůsob interval tomu, kolik práce jsi ochotný ztratit, a pak drž dva týdny dumpů, aby šlo obnovit i problém zavedený minulé úterý.
Obsahuje záloha serveru z panelu i databázi?
Jen pokud je při běhu zálohy ve složce serveru dump databáze. Archiv obsahuje soubory; databáze je služba. Proto plán nejdřív pořídí dump a až potom zálohu.
Obnoví se dump z novější verze na starším serveru?
Často ne. Dumpy jsou kompatibilní dopředu, ne dozadu: obnovuj na stejnou hlavní verzi nebo novější a vždy použij nástroje z novějšího z obou konců. Aktualizace verzí plánuj jako dump, instalace, obnova, ověření, ne s předpokladem, že se soubor načte kamkoli.
Jak obnovím jedinou tabulku nebo kolekci?
U PostgreSQL pg_restore -t nazev_tabulky z dumpu ve formátu custom, po kontrole obsahu příkazem pg_restore -l. U MongoDB mongorestore --nsInclude='db.collection'. V obou případech nejdřív obnov do pomocné databáze a řádky přenes záměrně, protože cílená obnova neví nic o omezeních a odkazech, které na tu tabulku míří odjinud.
A co role a hesla?
pg_dump je neobsahuje; pg_dumpall --globals-only ano a patří do stejné úlohy zálohy. U MongoDB žijí uživatelé v databázi admin a vrací se přes --restoreDbUsersAndRoles. Obnova, která na ně zapomene, vyrobí funkční databázi, do které se vaše aplikace nemůže přihlásit. Kontrolní seznam zabezpečení databáze popisuje, kdo má mít které z nich.




Komentáře
Zcela anonymně: žádný účet, žádný e-mail, žádné cookie. Ukládáme jen jméno, které napíšeš, text a čas - nic dalšího. Počet odkazů je omezený a značkování se nevykresluje.