PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Lors de l'exécution de PITR, serait-il possible de mettre en pause/reprendre dans PostgreSQL ?

Oui, vraiment possible et géré intelligemment par PostgreSQL. Pour faire une démonstration, je dois d'abord suivre la technique standard de récupération ponctuelle dans PostgreSQL. Divers livres / articles / blogs ont été extrêmement bien présentés par des auteurs extraordinaires. Je n'entre donc pas dans les détails de la façon de le faire, mais je me dirige directement vers le sujet, c'est-à-dire comment faire une pause tout en récupérant avec la même technique. On peut dire que j'ai proposé une expression mathématique à partir de PITR comme "PITR =(dernière sauvegarde du système de fichiers (LFB) + archives WAL générées après LFB + WAL non archivés dans $PGDATA/pg_xlogs actuels)". Pour une meilleure compréhension, j'ai mis cela en graphique, à la lumière du fait que cela éclaircit davantage la pensée :(Désolé, ce blog est un peu long, sans le savoir, c'est arrivé en entrant dans les détails du concept)

Étapes PITR, qui vont suivre avec de légères modifications dont je parle bientôt :

Étape 1. Restaurer la sauvegarde au niveau du système de fichiers (FSB) la plus récente à n'importe quel emplacement où la récupération est prévue.
Étape 2. Si FSB est tar, décompressez-le et nettoyez le répertoire pg_xlog en laissant archive_status. Si la sauvegarde a exclu ce répertoire, alors créez le répertoire pg_xlog vide dans FSB.
Étape 3. Copiez les WAL non archivés du cluster $PGDATA/pg_xlog dans $FSB/pg_xlog (Étape 2)
Étape 4. Supprimez le fichier postmaster.pid du répertoire FSB.
Étape 5. Créez le fichier recovery.conf dans le répertoire FSB.
Étape 6. Démarrez le cluster (FSB).

Nous devrions nous poser la question, lors de la pause de la récupération nécessaire ?. Peut-être, pour empêcher plusieurs restaurations de base ou récupération aval, mais vérifier entre ou annuler les données ou l'intérêt d'une table particulière pour voir jusqu'où elle a récupéré :). N'oubliez pas que la pause dans la récupération signifie qu'elle permet de se connecter pendant la récupération. Pour décrire cela, j'ai reproduit une situation dans le graphique d'une amélioration particulière des lignes d'un tableau jusqu'à un accident.

D'après le diagramme ci-dessus, les lignes d'une table DEMO agréables étaient de 10 00 000 lors de la sauvegarde au niveau du système de fichiers ($ PGDATA) et de 40 00 000 lignes avant le crash. Dans ma machine virtuelle locale, j'ai fait la situation sur le terrain de TIME au lieu de date.

Prérequis :
1. Sauvegarde au niveau du système de fichiers lorsque les tables DEMO ont 10 00 000 lignes.
2. À partir de ce moment, les archives WAL avant le crash où la table DEMO avait 40 00 000 lignes.
3. Emplacement des archives WAL :/opt/PostgreSQL/9.3/archives.
4. Répertoire de données :/opt/PostgreSQL/9.3/data (PGDATA)
5. Emplacement de sauvegarde :/opt/PostgreSQL/9.3/backups

Gardez à l'esprit que le travail avec la récupération en pause nécessite des modifications obligatoires sur le cluster principal ($PGDATA) "wal_level" défini sur "hot_standby" et sur le cluster de récupération (sauvegarde au niveau du système de fichiers) "hot_standby" défini sur "ON". J'ai apporté ces modifications au cluster principal, redémarré le cluster pour qu'il prenne effet et lancé la sauvegarde. Si cela ne vous dérange pas, notez qu'il s'agit simplement d'une démo, donc mes archives WAL pourraient ne pas être un nombre gigantesque car elles sont en petit nombre. J'ai également répertorié ici les archives WAL, qui ont été générées à partir du moment de la sauvegarde jusqu'au plantage.

-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

État actuel des archives WAL et $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

Très bien maintenant, nous avons la copie de sauvegarde, insérons quelques enregistrements en trois parties en notant l'heure, cela aidera donc à suspendre la récupération et à voir en plus les WAL produits à partir de l'époque du 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)

Vérifier le nombre de WAL produits lors de 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

Supposons qu'à ce stade, un incident se soit produit et que vous deviez effectuer une récupération à l'aide des archives FSB + WAL + WAL non archivés (le cas échéant). Pendant la récupération, je souhaite faire une pause trois fois pour voir chaque récupération de 20,00,000, 30,00,000 et 40,00,000 lignes de la table DEMO en me connectant à la base de données en mode LECTURE SEULE. Pour chaque reprise de récupération, un redémarrage du cluster de récupération est nécessaire en passant à une nouvelle chronologie dans recovery.conf/recovery_target_time. De plus, dans $FSB/postgresql.conf, nous devons définir hot_standby=on. Voici mon fichier 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'

Commençons la récupération pour 20 000 000 enregistrements :

-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

Cool, voyez dans les journaux qu'il a fait une pause et un ASTUCE intelligent demandant de reprendre. Ici, si la récupération a été satisfaisante, vous pouvez la reprendre en appelant "select pg_xlog_replay_resume();" (vous pouvez la vérifier). Ne reprenons pas maintenant, mais vérifions le nombre de lignes récupérées en se connectant au serveur.

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

Bon, il a atteint le point et s'est arrêté là où j'ai demandé. Faisons un pas de plus pour récupérer 30 000 000 lignes. Maintenant, définissez la prochaine chronologie dans recovery.conf/recovery_target_time et redémarrez le 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)

Bien…, donnons la dernière tentative de pause à 40 00 000 lignes.

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)

Oups, que s'est-il passé, pourquoi n'a-t-il pas fait une pause et qu'est-ce qu'il se plaint ?. Gardez à l'esprit que si aucune archive WAL n'est présente au moment de recovery_target_time, elle ne s'arrêtera pas et s'attendra à ce qu'elle soit arrivée au dernier point et ouvre la base de données pour READ/WRITE. Dans les journaux, sans trop s'étirer, il cherchait le fichier "00000001000000000000002C" qui n'est pas disponible, car à ce moment-là, le cluster s'est écrasé. Certains peuvent ne pas reconnaître ce comportement, mais son fait et son sens lorsqu'aucune archive WAL n'est présente, il n'y a aucune raison de suspendre la récupération. S'il est nécessaire de faire une pause même après l'absence d'archives WAL, utilisez alors standby_mode='on' (HOT_STANDBY), dans cette méthode, il ne sortira pas de la récupération mais attendra les archives WAL.

J'espère que cela a été utile.