sql >> Database teknologi >  >> RDS >> PostgreSQL

PostgreSQL Incremental Backup og Point-In-Time Recovery

PostgreSQL kommer med muligheden for at lave trinvise sikkerhedskopier og point-in-timer-gendannelse ud af boksen. Læs videre for at lære mere om indstillingerne og procedurerne for at opnå dette.

Det starter med WAL-filer

WAL står for Write Ahead Log . WAL'er bruges i næsten alle moderne RDBMS-systemer til at levere holdbare og atomare transaktioner.

Ændringer af data indeholdt i en PostgreSQL-databaseklynge, der administreres af en enkelt PostgreSQL-serverproces, er kun mulige via transaktioner. Ændringerne i dataene ved transaktioner registreres som en ordnet sekvens af WAL-poster . Disse poster skrives til filer med fast længde kaldet WAL-segmentfiler , eller blot WAL-filer .

WAL-filer live i $PGDATA/pg_wal , hvor $PGDATA er databiblioteket for databaseklyngen. På en standard Debian-installation er WAL-filmappen for hovedklyngen for eksempel /var/lib/postgresql/10/main/pg_wal . Her ser det ud som:

# 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

WAL-filer genereres trinvist i rækkefølge, startende fra klyngeoprettelse. De bliver ved med at blive genereret, så længe der sker ændringer i klyngen. WAL-filmekanismen er vigtig for PostgreSQL's funktion og kan ikke slås fra.

Efter at ændringerne først er skrevet ud som WAL-poster, skal de anvendes på repræsentationen på disken af ​​selve dataene. Denne proces kaldescheckpointing , og sker automatisk i baggrunden (det kan også tvinges manuelt). Punktet, indtil checkpointing blev udført, kaldesREDO-punktet . Checkpointing er også en væsentlig del af Postgres arkitektur og kan ikke slås fra.

WAL-filopbevaring

Under normal drift af PostgreSQL-serveren bliver WAL-filer ved med at blive skrevet ind i pg_wal vejviser. Men hvorfor have dem i nærheden?

En grund er crash recovery. Hvis PostgreSQL-serveren går ned og genstarter, begynder den at anvende ændringer fra WAL-poster i datafilerne (checkpointing) siden det sidste REDO-punkt. Dette garanterer, at datafilerne er i overensstemmelse med den sidst gennemførte transaktion.

En anden grund er relateret til streaming replikering. Streaming-replikering fungerer ved at sende WAL-poster over til standby servere, som gemmer disse lokalt og udfører kontrolpunkter. Standbys kan halte bagefter den server, de replikerer fra (kaldet den primære). ). For eksempel, hvis den primære har genereret 100 WAL-records, og standbyen har modtaget og anvendt de første 80, skal de seneste20 være tilgængelige, så standbyen kan modtage og anvende fra record 81 og fremefter.

Men de meget gamle WAL-filer kan vel slettes? Ja. PostgreSQL kan blive instrueret til at beholde de seneste WAL-filer og slette de ældre. Der er tre relevante konfigurationsmuligheder:

  • wal_keep_segments - indstiller minimumsantallet af seneste WAL-filer til at blive bevaret i WAL-filmappen
  • max_wal_size - angiver den maksimale samlede størrelse af WAL-filer i WAL-filmappen. Hvis dette overskrides, slettes ældre. Der kan dog være årsager (herunder en høj værdi for wal_keep_segments ), der kan forhindre denne indstilling i at blive respekteret.
  • min_wal_size - angiver en minimumsstørrelse for WAL-filer. Så længe den faktiske størrelse forbliver under denne værdi, slettes ingen filer.

I det virkelige liv er det ikke muligt eller påkrævet at gemme alle tidligere WAL-filer under pg_wal bibliotek.

WAL-filarkivering

Den reelle værdi af WAL-filer er, at de er en strøm af ændringer, der kan optages og afspilles igen for at få en ensartet replika af en PostgreSQL-klynge. PostgreSQL giver en måde, hvorpå vi kan kopiere (eller "arkivere") hver WAL-fil, efter den er modtaget oprettet – archive_command konfigurationsmulighed.

Denne indstilling specificerer en shell-kommandostreng, der påkaldes efter hver WAL-fil er oprettet. Her er nogle eksempler:

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

Der er også 2 andre muligheder, som skal indstilles:

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

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

WAL-komprimering

Du kan komprimere WAL-filerne, før du kopierer dem til en langsigtet/sikker lagerplacering. Der er dog en mulighed kaldet wal_compression . Aktivering af denne vil få PostgreSQL til at komprimere de individuelle WAL-poster i WAL-filerne. Selve WAL-filerne vil være af samme størrelse (typisk 16 MB), men vil indeholde en sekvens af komprimerede poster i stedet for almindelige poster.

Kontinuerlig arkivering

WAL-arkivering kaldes også kontinuerlig arkivering og er i kraft,inkrementel backup .

Før du starter denne proces med trinvis sikkerhedskopiering, kræves en fuld sikkerhedskopiering. Dette etablerer en baseline, hvorefter WAL-filer kan gendannes trinvist. En fuld sikkerhedskopi kan tages enten ved:

  • lukning af Postgres-serverprocessen og kopiering af klyngedatamappen (samtidig med at tilladelserne bevares), eller
  • ved at bruge pg_basebackup på en kørende Postgres-server.

Point-in-Time-Recovery (PITR)

PITR refererer til PostgreSQL's evne til at starte fra gendannelse af en fuld sikkerhedskopi og derefter gradvist hente og anvende arkiverede WAL-filer op til et specificeret tidsstempel.

For at gøre dette skal vi oprette en fil kaldet "recovery.conf" i det gendannede klyngedatabibliotek og starte en Postgres-server for det databibliotek. Recovery.conf-filen indeholder måltidsstemplet og ser sådan ud:

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

gendan_kommando specificerer, hvordan man henter en WAL-fil, der kræves af PostgreSQL. Det er det omvendte af archive_command. recovery_target_time angiver tidspunktet, indtil vi har brug for ændringerne.

Når en PostgreSQL-serverproces starter op og opdager en recovery.conf fil i databiblioteket, starter den op i en speciel tilstand kaldet "gendannelsestilstand". Når den er i gendannelsestilstand, afvises klientforbindelser. Postgres henter WAL-filer og anvender dem, indtil gendannelsesmålet (i dette tilfælde ændringer op til det angivne tidsstempel) er opnået. Når målet er nået, sætter serveren som standard WAL-genafspilning på pause (andre handlinger er mulige). På dette tidspunkt er det meningen, at du skal undersøge tilstanden af ​​gendannelsen, og hvis alt ser ok ud, skal du fortsætte pausen for at afslutte gendannelsestilstand og fortsætte normal drift.

Sæt det hele sammen

Alt det var en hel masse teori og tekst, lad os prøve det for at se, hvordan det hele fungerer i praksis.

Lad os først initialisere en ny klynge:

/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

Vi opretter også en mappe, der vil fungere som vores sikre lagerplads. Lad os kalde dette "arkiv".

/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

Vi skal konfigurere de arkivindstillinger, vi diskuterede tidligere, før vi kan starte serveren. Så lad os tilføje følgende til slutningen af ​​clus1/postgres.conf :

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

Vores arkivkommando kopierer simpelthen WAL-filen til den arkivmappe, vi oprettede tidligere.

Vi har også tilføjet archive_timeout indstilling. Normalt oprettes en WAL-fil kun, når der er nok WAL-poster til at fylde en 16 MB WAL-fil. Dette betyder, at for servere med få skrivninger, skal du muligvis vente længe på, at en WAL-fil bliver oprettet. Indstillingen archive_timeout fortæller Postgres, at den skal opret en WAL-fil hvert så mange sekund, uanset om den er fuld eller ej.

Her har vi sat dette til 60 (sekunder), men dette er kun til demoen! Du vil typisk aldrig holde det så lavt.

Lad os også lave en kopi af "clus1". Dette svarer til en fuld backup.

/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

Nu kan vi starte klyngen:

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

Lad os tilføje nogle data.

/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

Bemærk at klokken nu er 14:05. Lad os tjekke, om vores arkivkommando virker:

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

Ja, vi har én enkelt arkivfil. Vores sidste ændring var kl. 14:05, lad os nu vente et par minutter og derefter foretage nogle flere ændringer.

/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

Så nu har vi tilføjet 100 flere rækker, kl. 14:16. Lad os stoppe serveren:

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

og tjek vores arkiv igen:

/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

Ser godt ud. Nu vil vi forsøge at lave en PITR-gendannelse af clus2 op til klokken 14:10.

Lad os først redigere clus2s postgres.conf og tilføje disse linjer til sidst:

port = 6001
archive_mode = off

For at afspille WAL-filerne igen, skal vi sætte PostgreSQL-serveren til clus2 (som vi ikke har startet endnu) i gendannelsestilstand. For at gøre dette skal du oprette filen kaldet "recovery.conf" i clus2:

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

Dette indeholder gendan_kommando som gør det modsatte af den tidligerearkivkommando , nemlig kopiering af den ønskede fil fra arkivbiblioteket til pg_wal-mappen.

Vi har også indstillet recovery_target_time til 14:10.

Nu starter vi clus2:

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

For at se, hvad der skete, lad os undersøge logfilen:

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

Gendannelsen var hurtig (i det virkelige liv kan det tage timer eller dage), og log angiver, at den er stoppet før en bestemt transaktion (som har et tidsstempel på> 14:10). Den siger også, at genoprettelsen er sat på pause og skal fortsættes manuelt.

Lad os undersøge dataene:

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

Vi ser, at der kun er 10000 rækker. 14:16 havde vi tilføjet 100 mere, som ikke er vist i tabellen.

Det ser godt ud, så lad os genoptage:

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

(1 row)

Logfilen rapporterer nu, at gendannelsen er fuldført, og normal drift er gendannet:

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

Og vi har med succes gendannet klyngen indtil et bestemt tidspunkt!

Yderligere læsning

Her er et par udgangspunkter for at finde ud af mere om WAL-arkivering, gendannelsestilstand og PITR:

  • Docs:RecoveryConfiguration
  • Dokumenter:Kontinuerlig arkivering og PITR
  • Kapitel 9 fra "The Internals ofPostgreSQL"-bogen
  • Værktøjer:WAL-E,WAL-G, Barman

  1. Opdater erklæring med indre joinforbindelse på Oracle

  2. Dynamisk datamaskering i SQL Server til avancerede brugere

  3. Gentagelse af rækker baseret på kolonneværdi i hver række

  4. MySQL-forespørgsel for at få bedst sælgende produkter