sql >> Databáze >  >> RDS >> PostgreSQL

PostgreSQL Incremental Backup a Point-In-Time Recovery

PostgreSQL přichází s možností provádět přírůstkové zálohování a obnovu v určitém okamžiku ihned po vybalení. Čtěte dále, abyste se dozvěděli více o nastaveních a postupech, jak toho dosáhnout.

Začíná se soubory WAL

WAL znamená Write Ahead Log . WAL se používají téměř ve všech moderních systémech RDBMS k zajištění trvalých a atomických transakcí.

Změny dat obsažených v databázovém clusteru PostgreSQL spravovaném jediným procesem serveru PostgreSQL jsou možné pouze prostřednictvím transakcí. Úpravy provedené v datech transakcemi jsou zaznamenány jako uspořádaná sekvence záznamů WAL . Tyto záznamy se zapisují do souborů s pevnou délkou, které se nazývají soubory segmentů WAL , nebo jednoduše soubory WAL .

Soubory WAL žijí v $PGDATA/pg_wal , kde $PGDATA je datový adresář pro databázový cluster. Například ve výchozí instalaci Debianu je adresář souborů WAL pro hlavní cluster /var/lib/postgresql/10/main/pg_wal . Tady to vypadá:

# pwd
/var/lib/postgresql/10/main/pg_wal
# ls -l
total 278532
-rw------- 1 postgres postgres 16777216 May  7 08:48 00000001000000000000000B
-rw------- 1 postgres postgres 16777216 May  7 10:08 00000001000000000000000C
-rw------- 1 postgres postgres 16777216 May  7 10:08 00000001000000000000000D
-rw------- 1 postgres postgres 16777216 May  7 10:08 00000001000000000000000E
-rw------- 1 postgres postgres 16777216 May  7 10:08 00000001000000000000000F
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000010
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000011
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000012
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000013
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000014
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000015
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000016
-rw------- 1 postgres postgres 16777216 May  7 10:08 000000010000000000000017
-rw------- 1 postgres postgres 16777216 May 16 20:52 000000010000000000000018
-rw------- 1 postgres postgres 16777216 May 16 20:56 000000010000000000000019
-rw------- 1 postgres postgres 16777216 May 26 08:52 00000001000000000000001A
-rw------- 1 postgres postgres 16777216 Jun  2 09:59 00000001000000000000001B
drwx------ 2 postgres postgres     4096 Mar 30 10:06 archive_status

Soubory WAL jsou generovány postupně, v pořadí, počínaje vytvářením clusteru. Generují se tak dlouho, dokud v clusteru dochází k úpravám. Mechanismus souborů WAL je nezbytný pro fungování PostgreSQL a nelze jej vypnout.

Poté, co jsou změny poprvé zapsány jako záznamy WAL, je třeba je aplikovat na samotnou reprezentaci dat na disku. Tento proces se nazývákontrolní bod , a děje se na pozadí automaticky (lze také vynutit ručně). Bod, do kterého bylo provedeno kontrolní bodování, se nazývábod REDO . Checkpointing je také nezbytnou součástí architektury Postgres a nelze jej vypnout.

Uchování souboru WAL

Při normálním provozu serveru PostgreSQL se soubory WAL budou neustále zapisovat do pg_wal adresář. Ale proč je mít kolem sebe?

Jedním z důvodů je zotavení po havárii. Pokud se PostgreSQL server zhroutí a restartuje, začne aplikovat změny ze záznamů WAL do datových souborů (kontrolní bod) od posledního bodu REDO. To zaručuje, že datové soubory jsou konzistentní s poslední dokončenou transakcí.

Další důvod souvisí s replikací streamování. Streamování replikace funguje odesláním záznamů WAL do pohotovostního režimu servery, které je ukládají lokálně a provádějí kontrolní body. Pohotovostní režimy mohou zaostávat za serverem, ze kterého se replikují (tzv. primární). ). Pokud například primární vygeneroval 100 záznamů WAL a pohotovostní režim přijal a použil prvních 80, musí být k dispozici nejnovějších 20, aby pohotovostní režim mohl přijímat a používat od záznamu 81 a dále.

Ale velmi staré soubory WAL lze smazat? Ano. PostgreSQL může být instruován, aby uchoval nejnovější soubory WAL a odstranil ty starší. Existují tři relevantní možnosti konfigurace:

  • wal_keep_segments - nastaví minimální počet posledních souborů WAL, které mají být uloženy v adresáři souborů WAL
  • max_wal_size - určuje maximální celkovou velikost souborů WAL v adresáři souborů WAL. Pokud je toto překročeno, starší jsou smazány. Mohou však existovat důvody (včetně vysoké hodnoty pro wal_keep_segments ), které mohou zabránit respektování tohoto nastavení.
  • min_wal_size - určuje minimální celkovou velikost souborů WAL. Dokud skutečná velikost zůstane pod touto hodnotou, nebudou smazány žádné soubory.

V reálném životě není možné nebo nutné uložit všechny předchozí soubory WAL pod pg_wal adresář.

Archivace souborů WAL

Skutečná hodnota souborů WAL je v tom, že jde o proud změn, které lze zaznamenat a přehrát, abychom získali konzistentní repliku clusteru PostgreSQL. PostgreSQL poskytuje způsob, kterým můžeme zkopírovat (nebo „archivovat“) každý soubor WAL poté, co se dostane. vytvořeno – příkaz_archive možnost konfigurace.

Tato volba určuje řetězec příkazů shellu, který je vyvolán po vytvoření každého souboru WAL. Zde je několik příkladů:

# Copy the file to a safe location (like a mounted NFS volume)
archive_command = 'cp %p /mnt/nfs/%f'

# Not overwriting files is a good practice
archive_command = 'test ! -f /mnt/nfs/%f && cp %p /mnt/nfs/%f'

# Copy to S3 bucket
archive_command = 's3cmd put %p s3://BUCKET/path/%f'

# Copy to Google Cloud bucket
archive_command = 'gsutil cp %p gs://BUCKET/path/%f'

# An external script
archive_command = '/opt/scripts/archive_wal %p'

Existují také 2 další možnosti, které je třeba nastavit:

# this must be "on" to enable WAL archiving
archive_mode = on

# has to be "replica" (default) or "logical" for WAL archiving
wal_level = replica

Komprese WAL

Soubory WAL můžete před zkopírováním do dlouhodobého/bezpečného úložiště zkomprimovat. Existuje však možnost nazvaná wal_compression . Toto zapnutí způsobí, že PostgreSQL komprimuje jednotlivé záznamy WAL v souborech WAL. Samotné soubory WAL budou mít stejnou velikost (obvykle 16 MB), ale budou obsahovat sekvenci komprimovaných záznamů spíše než prosté záznamy.

Nepřetržité archivování

Archivace WAL se také nazývá průběžná archivace a je v platnosti,přírůstkové zálohování .

Před zahájením tohoto procesu přírůstkového zálohování je vyžadována úplná záloha. Tím se stanoví základní linie, podle které lze postupně obnovovat soubory WAL. Úplnou zálohu lze provést buď:

  • vypnutí procesu serveru Postgres a zkopírování datového adresáře clusteru (při zachování oprávnění), nebo
  • pomocí pg_basebackup na běžícím serveru Postgres.

Point-In-Time-Recovery (PITR)

PITR odkazuje na schopnost PostgreSQL začít obnovením úplné zálohy a poté postupně načítat a aplikovat archivované soubory WAL až do určeného časového razítka.

K tomu musíme vytvořit soubor s názvem „recovery.conf“ v datovém adresáři restoredcluster a spustit server Postgres pro tento datový adresář. Soubor recovery.conf obsahuje cílové časové razítko a vypadá takto:

restore_command = 'cp /tmp/demo/archive/%f "%p"'
recovery_target_time = '2019-06-04 14:10:00'

příkaz_restore určuje, jak načíst soubor WAL požadovaný PostgreSQL. Je to opak příkazu archive_command. recovery_target_time určuje čas, do kdy potřebujeme změny.

Když se spustí proces serveru PostgreSQL a objeví recovery.conf v datovém adresáři se spustí ve speciálním režimu zvaném „recovery mode“. V režimu obnovy jsou klientská připojení odmítnuta. Postgres načítá soubory WAL a aplikuje je, dokud není dosaženo cíle obnovy (v tomto případě se změní až do zadaného časového razítka). Když je dosaženo cíle, server ve výchozím nastavení pozastaví přehrávání WAL (jsou možné i jiné akce). V tomto okamžiku byste měli prozkoumat stav obnovy a pokud vše vypadá v pořádku, zrušte pozastavení pro ukončení režimu obnovy a pokračujte v normálním provozu.

Spojení všeho dohromady

Všechno to byla spousta teorie a textu, pojďme si to vyzkoušet, abychom viděli, jak to celé funguje v praxi.

Nejprve inicializujeme nový cluster:

/tmp/demo$ pg_ctl -D clus1 initdb
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.

The database cluster will be initialized with locale "C.UTF-8".
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "english".

Data page checksums are disabled.

creating directory clus1 ... ok
creating subdirectories ... ok
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting dynamic shared memory implementation ... posix
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok

WARNING: enabling "trust" authentication for local connections
You can change this by editing pg_hba.conf or using the option -A, or
--auth-local and --auth-host, the next time you run initdb.

Success. You can now start the database server using:

    /usr/lib/postgresql/10/bin/pg_ctl -D clus1 -l logfile start

Vytvoříme také adresář, který bude sloužit jako naše bezpečné úložiště. Říkejme tomu „archiv“.

/tmp/demo$ mkdir archive
/tmp/demo$ ls -l
total 8
drwxr-xr-x  2 postgres postgres 4096 Jun  4 14:02 archive
drwx------ 19 postgres postgres 4096 Jun  4 14:02 clus1

Než budeme moci spustit server, musíme nakonfigurovat nastavení archivu, o kterém jsme hovořili dříve. Přidejme tedy na konec clus1/postgres.conf následující :

port = 6000
wal_level = logical
archive_mode = on
archive_command = 'cp %p /tmp/demo/archive/%f'
archive_timeout = 60

Náš archivní příkaz jednoduše zkopíruje soubor WAL do archivního adresáře, který jsme vytvořili dříve.

Také jsme přidali archive_timeout nastavení. Obvykle se soubor WAL vytvoří pouze tehdy, když je k dispozici dostatek záznamů WAL k naplnění 16 MB souboru WAL. To znamená, že u serverů s malým počtem zápisů budete možná muset čekat dlouhou dobu na vytvoření souboru WAL. Nastavení archive_timeout říká Postgresu, že musí vytvořit soubor aWAL každých tolik sekund, bez ohledu na to, zda je plný nebo ne.

Zde jsme to nastavili na 60 (sekund), ale to je pouze pro demo! Obvykle byste to nikdy nechtěli držet tak nízko.

Udělejme také kopii „clus1“. Toto je ekvivalent plné zálohy.

/tmp/demo$ cp -Rp clus1 clus2
/tmp/demo$ ls -l
total 12
drwxr-xr-x  2 postgres postgres 4096 Jun  4 14:02 archive
drwx------ 19 postgres postgres 4096 Jun  4 14:03 clus1
drwx------ 19 postgres postgres 4096 Jun  4 14:03 clus2

Nyní můžeme spustit cluster:

/tmp/demo$ pg_ctl -D clus1 -l log1 start
waiting for server to start.... done
server started

Pojďme přidat nějaké údaje.

/tmp/demo$ psql -h /var/run/postgresql -p 6000 postgres
psql (10.8 (Ubuntu 10.8-0ubuntu0.18.04.1))
Type "help" for help.

postgres=# create database demo;
CREATE DATABASE
postgres=# \c demo
You are now connected to database "demo" as user "postgres".
demo=# create table tbl1 (col1 int);
CREATE TABLE
demo=# insert into tbl1 (col1) select generate_series(1, 10000);
INSERT 0 10000
demo=# select count(*) from tbl1;
 count
-------
 10000
(1 row)

demo=# select now();
              now
-------------------------------
 2019-06-04 14:05:05.657871+00
(1 row)

demo=# \q

Všimněte si, že čas je nyní 14:05. Pojďme zkontrolovat, zda náš příkaz pro archivaci funguje:

/tmp/demo$ ls -l archive/
total 16384
-rw------- 1 postgres postgres 16777216 Jun  4 14:04 000000010000000000000001

Ano, máme jeden archivní soubor. K naší poslední změně došlo ve 14:05, počkejte několik minut a pak proveďte další změny.

/tmp/demo$ psql -h /var/run/postgresql -p 6000 demo
psql (10.8 (Ubuntu 10.8-0ubuntu0.18.04.1))
Type "help" for help.

demo=# select now();
              now
-------------------------------
 2019-06-04 14:16:06.093859+00
(1 row)

demo=# select count(*) from tbl1;
 count
-------
 10000
(1 row)

demo=# insert into tbl1 (col1) select generate_series(1, 100);
INSERT 0 100
demo=# select count(*) from tbl1;
 count
-------
 10100
(1 row)

demo=# \q

Takže nyní jsme přidali 100 dalších řádků ve 14:16. Zastavme server:

/tmp/demo$ pg_ctl -D clus1 stop
waiting for server to shut down.... done
server stopped
/tmp/demo$

a znovu se podívejte do našeho archivu:

/tmp/demo$ ls -l archive/
total 65536
-rw------- 1 postgres postgres 16777216 Jun  4 14:04 000000010000000000000001
-rw------- 1 postgres postgres 16777216 Jun  4 14:05 000000010000000000000002
-rw------- 1 postgres postgres 16777216 Jun  4 14:09 000000010000000000000003
-rw------- 1 postgres postgres 16777216 Jun  4 14:16 000000010000000000000004

Vypadá dobře. Nyní se pokusíme provést obnovu PITR clus2 až do času 14:10.

Nejprve upravíme clus2's postgres.conf a na konec přidáme tyto řádky:

port = 6001
archive_mode = off

Aby bylo možné znovu přehrát soubory WAL, musíme server PostgreSQL pro clus2 (který jsme ještě nespustili) uvést do režimu obnovy. Chcete-li to provést, vytvořte soubor s názvem „recovery.conf“ v clus2:

/tmp/demo$ cat clus2/recovery.conf
restore_command = 'cp /tmp/demo/archive/%f "%p"'
recovery_target_time = '2019-06-04 14:10:00'

Toto obsahuje příkaz obnovení což dělá opak dřívějšího příkazuarchive_command , jmenovitě zkopírování požadovaného souboru z archivního adresáře do adresáře pg_wal.

Nastavili jsme také recovery_target_time do 14:10.

Nyní začneme clus2:

/tmp/demo$ pg_ctl -D clus2 -l log2 start
waiting for server to start.... done
server started

Chcete-li zjistit, co se stalo, prozkoumejte soubor protokolu:

/tmp/demo$ cat log2
2019-06-04 14:19:10.862 UTC [10513] LOG:  listening on IPv4 address "127.0.0.1", port 6001
2019-06-04 14:19:10.864 UTC [10513] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.6001"
2019-06-04 14:19:10.883 UTC [10514] LOG:  database system was shut down at 2019-06-04 14:02:31 UTC
2019-06-04 14:19:10.883 UTC [10514] LOG:  starting point-in-time recovery to 2019-06-04 14:10:00+00
2019-06-04 14:19:10.903 UTC [10514] LOG:  restored log file "000000010000000000000001" from archive
2019-06-04 14:19:10.930 UTC [10514] LOG:  consistent recovery state reached at 0/16383E8
2019-06-04 14:19:10.930 UTC [10514] LOG:  redo starts at 0/16383E8
2019-06-04 14:19:10.931 UTC [10513] LOG:  database system is ready to accept read only connections
2019-06-04 14:19:11.037 UTC [10514] LOG:  restored log file "000000010000000000000002" from archive
2019-06-04 14:19:11.079 UTC [10514] LOG:  restored log file "000000010000000000000003" from archive
2019-06-04 14:19:11.122 UTC [10514] LOG:  restored log file "000000010000000000000004" from archive
2019-06-04 14:19:11.141 UTC [10514] LOG:  recovery stopping before commit of transaction 559, time 2019-06-04 14:16:24.875517+00
2019-06-04 14:19:11.141 UTC [10514] LOG:  recovery has paused
2019-06-04 14:19:11.141 UTC [10514] HINT:  Execute pg_wal_replay_resume() to continue.

Obnova byla rychlá (ve skutečném životě to může trvat hodiny nebo dny) a protokol uvádí, že se zastavil před konkrétní transakcí (která má časové razítko> 14:10). Také to říká, že obnova je pozastavena a je třeba v ní ručně pokračovat.

Podívejme se na data:

/tmp/demo$ psql -h /var/run/postgresql -p 6001 demo
psql (10.8 (Ubuntu 10.8-0ubuntu0.18.04.1))
Type "help" for help.

demo=# select count(*) from tbl1;
 count
-------
 10000
(1 row)

Vidíme, že existuje pouze 10 000 řádků. Ve 14:16 jsme přidali 100 dalších, které se neobjevily v tabulce.

Vypadá to dobře, takže pokračujeme:

demo=# select pg_wal_replay_resume();
 pg_wal_replay_resume
----------------------

(1 row)

Soubor protokolu nyní hlásí, že obnova je dokončena a normální operace jsou obnoveny:

2019-06-04 14:20:26.219 UTC [10514] LOG:  redo done at 0/4002160
2019-06-04 14:20:26.219 UTC [10514] LOG:  last completed transaction was at log time 2019-06-04 14:05:28.813325+00
cp: cannot stat '/tmp/demo/archive/00000002.history': No such file or directory
2019-06-04 14:20:26.228 UTC [10514] LOG:  selected new timeline ID: 2
2019-06-04 14:20:26.272 UTC [10514] LOG:  archive recovery complete
cp: cannot stat '/tmp/demo/archive/00000001.history': No such file or directory
2019-06-04 14:20:26.388 UTC [10513] LOG:  database system is ready to accept connections

A úspěšně jsme obnovili cluster až do stanovené doby!

Další čtení

Zde je několik výchozích bodů, jak zjistit více o archivaci WAL, režimu obnovy a PITR:

  • Dokumenty:RecoveryConfiguration
  • Dokumenty:Průběžná archivace a PITR
  • Kapitola 9 z knihy „The Internals of PostgreSQL“
  • Nástroje:WAL-E, WAL-G, Barman

  1. Jak vrátit více hodnot v jednom sloupci (T-SQL)?

  2. Závažná chyba Wordpress:Nezachycená chyba:Volání nedefinované funkce mysql_connect() v /wp-includes/wp-db.php:1570

  3. Jaký je rozdíl mezi Views a Materialized Views v Oracle?

  4. Jak snadno nasadit TimescaleDB