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

Durante l'esecuzione di PITR, sarebbe possibile mettere in pausa/riprendere in PostgreSQL?

Sì, davvero possibile e gestito in modo intelligente da PostgreSQL. Per dimostrarlo, prima devo seguire la tecnica standard di Point in Time Recovery in PostgreSQL. Vari libri/articoli/blog sono stati dimostrati molto bene da autori straordinari, quindi non entro nei dettagli su come farlo, tuttavia, andando direttamente all'argomento, ovvero come fare una pausa mentre si riprende con la stessa tecnica. Probabilmente, ho presentato un'espressione matematica da PITR come "PITR =(Last Filesystem Backup (LFB) + archivi WAL generati dopo LFB + WAL non archiviati negli attuali $PGDATA/pg_xlogs)". Per una migliore comprensione, ho messo questo in grafico, alla luce del fatto che chiarisce di più il pensiero:(scusate, questo blog è un po' lungo, inconsapevolmente è successo mentre andavo nei dettagli del concetto)

Passi PITR, che seguiranno con lievi modifiche di cui parlerò presto:

Passaggio 1. Ripristina il backup a livello di file system (FSB) più recente in qualsiasi posizione in cui è prevista l'esecuzione del ripristino.
Fase 2. Se FSB è tar, allora decomprimilo e pulisci la directory pg_xlog lasciando archive_status. Se il backup ha escluso questa directory, creare la directory pg_xlog vuota in FSB.
Passaggio 3. Copia i WAL non archiviati dal cluster danneggiato $PGDATA/pg_xlog in $FSB/pg_xlog (Passaggio 2)
Passaggio 4. Elimina postmaster.pid dalla directory FSB.
Passaggio 5. Crea il file recovery.conf nella directory FSB.
Passaggio 6. Avvia il cluster (FSB).

Dovremmo porre domande, quando sospendiamo il recupero richiesto?. Forse, per prevenire più restauri di base o il ripristino del rollforward, ma controlla o ripristina i dati o l'interesse di una tabella particolare per vedere fino a che punto è stato recuperato :). Ricorda, mettere in pausa il ripristino significa che consente di connettersi durante il ripristino. Per delineare questo, ho riprodotto una situazione nel grafico di un particolare miglioramento delle righe della tabella fino a un incidente.

Dal diagramma sopra, è accettabile che le righe di una tabella DEMO fossero 10.00.000 quando è stato eseguito il backup a livello di file system ($ PGDATA) e 40.00.000 di righe prima dell'arresto anomalo. Nella mia macchina virtuale locale, ho creato la situazione sulla base di TIME anziché di data.

Prerequisito:
1. Backup a livello di file system quando tabelle DEMO con 10.00.000 di righe.
2. Da quel momento in poi, gli archivi WAL prima dell'arresto anomalo in cui la tabella DEMO ha 40.00.000 di righe.
3. Posizione degli archivi WAL:/opt/PostgreSQL/9.3/archives.
4. Directory dati:/opt/PostgreSQL/9.3/data (PGDATA)
5. Posizione di backup:/opt/PostgreSQL/9.3/backups

Tieni presente che, lavorando con il ripristino in pausa, sono necessarie modifiche obbligatorie sul cluster principale ($PGDATA) "wal_level" impostato su "hot_standby" e sul cluster di ripristino (backup a livello di file system) "hot_standby" impostato su "ON". Ho apportato queste modifiche al cluster principale, riavviato il cluster per rendere effettive e avviato il backup. Se non ti dispiace prendere nota, è semplicemente una demo, quindi i miei archivi WAL potrebbero non essere numeri giganteschi in quanto sono in pochi numeri. Ho elencato anche gli archivi WAL qui, che sono stati generati dal momento del backup fino all'arresto anomalo.

-bash-4.1$ psql -c "select count(*), now() from demo;"
count | now
---------+-------------------------------
1000000 | 2014-04-04 15:06:04.036928-07
(1 row)

-bash-4.1$ pg_basebackup -D /opt/PostgreSQL/9.3/backup/data_pitr -- I have my $PGDATA, $PGUSER, $PGPORT set, so its a straight command in my case
NOTICE: pg_stop_backup complete, all required WAL segments have been archived

Stato attuale degli archivi WAL e $PGDATA/pg_xlog

-bash-4.1$ ls -lrth /opt/PostgreSQL/9.3/archives
-rw------- 1 postgres postgres 16M Apr 4 16:01 00000001000000000000001C
-rw------- 1 postgres postgres 16M Apr 4 16:01 00000001000000000000001D
-rw------- 1 postgres postgres 289 Apr 4 16:06 00000001000000000000001E.000000C8.backup
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001E

-bash-4.1$ ls -lrth /opt/PostgreSQL/9.3/data/pg_xlog | tail -4
-rw------- 1 postgres postgres 289 Apr 4 16:06 00000001000000000000001E.000000C8.backup
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001E
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001F
drwx------ 2 postgres postgres 4.0K Apr 4 16:13 archive_status

Bene ora, abbiamo la copia di backup, consente di INSERIRE pochi record in tre parti annotando l'ora, quindi aiuterà a mettere in pausa il ripristino e vedere inoltre i WAL prodotti dai tempi di FSB.

-bash-4.1$ psql -c "insert into demo values (generate_series(1,1000000));"
INSERT 0 1000000
-bash-4.1$ psql -c "select count(*),now() from demo;"
count | now
---------+-------------------------------
2000000 | 2014-04-04 16:06:34.941615-07
(1 row)
-bash-4.1$ psql -c "insert into demo values (generate_series(1,1000000));"
INSERT 0 1000000
-bash-4.1$ psql -c "select count(*),now() from demo;"
count | now
---------+-------------------------------
3000000 | 2014-04-04 16:10:31.136725-07
(1 row)
-bash-4.1$ psql -c "insert into demo values (generate_series(1,1000000));"
INSERT 0 1000000
-bash-4.1$ psql -c "select count(*),now() from demo;"
count | now
---------+-------------------------------
4000000 | 2014-04-04 16:13:00.136725-07
(1 row)

Controlla il numero di WAL prodotte durante l'INSERT.

-bash-4.1$ ls -lrth /opt/PostgreSQL/9.3/archives
-rw------- 1 postgres postgres 289 Apr 4 16:06 00000001000000000000001E.000000C8.backup
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001E
-rw------- 1 postgres postgres 16M Apr 4 16:06 00000001000000000000001F
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000020
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000021
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000022
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000023
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000024
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000025
-rw------- 1 postgres postgres 16M Apr 4 16:06 000000010000000000000026
-rw------- 1 postgres postgres 16M Apr 4 16:10 000000010000000000000027
-rw------- 1 postgres postgres 16M Apr 4 16:10 000000010000000000000028
-rw------- 1 postgres postgres 16M Apr 4 16:10 000000010000000000000029
-rw------- 1 postgres postgres 16M Apr 4 16:10 00000001000000000000002A
-rw------- 1 postgres postgres 16M Apr 4 16:13 00000001000000000000002B

Supponiamo che a questo punto si sia verificato un incidente e devi eseguire il ripristino utilizzando gli archivi FSB + WAL + WAL non archiviati (se presenti). Durante il ripristino, voglio fare una pausa tre volte per vedere ogni ripristino di 20.00.000, 30.00.000 e 40.00.000 righe della tabella DEMO connettendomi al database in modalità SOLA LETTURA. Per ogni ripristino del ripristino è necessario un riavvio del cluster di ripristino passando alla nuova sequenza temporale in recovery.conf/recovery_target_time. Inoltre, in $FSB/postgresql.conf, dobbiamo impostare hot_standby=on. Ecco il mio file recovery.conf:

-bash-4.1$ more recovery.conf
pause_at_recovery_target = true
#recovery_target_time = '2014-04-04 16:06:34' # For 2 lakh records
#recovery_target_time = '2014-04-04 16:10:31' # For 3 lakh records
#recovery_target_time = '2014-04-04 16:13:00' # For 4 lakh records
restore_command = 'cp /opt/PostgreSQL/9.3/archives/%f %p'

Iniziamo il recupero per 20.00.000 di record:

-bash-4.1$ /opt/PostgreSQL/9.3/bin/pg_ctl -D /opt/PostgreSQL/9.3/data_pitr/ start
server starting

Now in logs:

-bash-4.1$ more postgresql-2014-04-04_162524.log
2014-04-04 16:25:24 PDT-24187---[] LOG: starting point-in-time recovery to 2014-02-06 18:48:56-08
2014-04-04 16:25:24 PDT-24187---[] LOG: restored log file "00000001000000000000001E" from archive
2014-04-04 16:25:24 PDT-24187---[] LOG: redo starts at 0/1E0000C8
2014-04-04 16:25:24 PDT-24187---[] LOG: consistent recovery state reached at 0/1E000190
2014-04-04 16:25:24 PDT-24185---[] LOG: database system is ready to accept read only connections
2014-04-04 16:25:24 PDT-24187---[] LOG: restored log file "00000001000000000000001F" from archive
2014-04-04 16:25:24 PDT-24187---[] LOG: restored log file "000000010000000000000020" from archive
2014-04-04 16:25:25 PDT-24187---[] LOG: restored log file "000000010000000000000021" from archive
2014-04-04 16:25:25 PDT-24187---[] LOG: restored log file "000000010000000000000022" from archive
2014-04-04 16:25:25 PDT-24187---[] LOG: recovery stopping before commit of transaction 1833, time 2014-04-04 16:06:23.893487-07
2014-04-04 16:25:25 PDT-24187---[] LOG: recovery has paused
2014-04-04 16:25:25 PDT-24187---[] HINT: Execute pg_xlog_replay_resume() to continue

Fantastico, vedi nei log che è stato messo in pausa e un SUGGERIMENTO intelligente che chiede di riprendere. Qui, se il ripristino è stato soddisfacente, puoi riprenderlo chiamando "select pg_xlog_replay_resume();"(Puoi verificarlo). Non riprendiamo ora, però controlliamo il numero di righe recuperate collegandoci al server.

-bash-4.1$ psql -c "select count(*),pg_is_in_recovery() from demo;"
count | pg_is_in_recovery
---------+-------------------
2000000 | t
(1 row)

Bene, è arrivato al punto e si è fermato dove avevo richiesto. Facciamo un altro passo avanti per recuperare 30.00.000 di righe. Ora, imposta la sequenza temporale successiva in recovery.conf/recovery_target_time e riavvia il cluster.

2014-04-04 16:28:40 PDT-24409---[] LOG:  restored log file "00000001000000000000002A" from archive
2014-04-04 16:28:40 PDT-24409---[] LOG: recovery stopping before commit of transaction 1836, time 2014-04-04 16:10:40.141175-07
2014-04-04 16:28:40 PDT-24409---[] LOG: recovery has paused
2014-04-04 16:28:40 PDT-24409---[] HINT: Execute pg_xlog_replay_resume() to continue.

-bash-4.1$ psql -c "select count(*),pg_is_in_recovery() from demo;"
count | pg_is_in_recovery
---------+-------------------
3000000 | t
(1 row)

Bene..., diamo l'ultimo tentativo di mettere in pausa a 40.00.000 di righe.

2014-04-04 20:09:07 PDT-4723---[] LOG:  restored log file "00000001000000000000002B" from archive
cp: cannot stat `/opt/PostgreSQL/9.3/archives/00000001000000000000002C': No such file or directory
2014-04-04 20:09:07 PDT-4723---[] LOG: redo done at 0/2B0059A0
2014-04-04 20:09:07 PDT-4723---[] LOG: last completed transaction was at log time 2014-04-04 16:11:12.264512-07
2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000001000000000000002B" from archive
2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000002.history" from archive
2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000003.history" from archive
2014-04-04 20:09:07 PDT-4723---[] LOG: restored log file "00000004.history" from archive
cp: cannot stat `/opt/PostgreSQL/9.3/archives/00000005.history': No such file or directory
2014-04-04 20:09:07 PDT-4723---[] LOG: selected new timeline ID: 5
cp: cannot stat `/opt/PostgreSQL/9.3/archives/00000001.history': No such file or directory
2014-04-04 20:09:07 PDT-4723---[] LOG: archive recovery complete
2014-04-04 20:09:08 PDT-4721---[] LOG: database system is ready to accept connections
2014-04-04 20:09:08 PDT-4764---[] LOG: autovacuum launcher started

-bash-4.1$ psql -c "select count(*),pg_is_in_recovery() from demo;"
count | pg_is_in_recovery
---------+-------------------
4000000 | f
(1 row)

Oops, cosa è successo, perché non si è fermato e cosa si lamenta?. Tieni presente che se nessun archivio WAL è presente al momento di recovery_target_time, non si fermerà e si aspetterà poiché è arrivato all'ultimo punto e apre il database per LETTURA/SCRITTURA. Nei log, senza molto allungamento, si scopre che stava cercando il file "000000010000000000000002C" che non è disponibile, perché in quel momento il cluster si è arrestato in modo anomalo. Alcuni potrebbero non riconoscere questo comportamento ma il suo fatto e ha senso quando non sono presenti archivi WAL, non c'è motivo per sospendere il ripristino. Se è necessario mettere in pausa anche dopo che non ci sono archivi WAL, utilizzare standby_mode='on' (HOT_STANDBY), in questo metodo non uscirà dal ripristino ma attende gli archivi WAL.

Spero sia stato utile.