Restauration PITR – Part 7

Je profite d’un week end de mauvais temps (m’empêchant de retourner en falaise 🙁 ) pour poursuivre mes articles sur Postgres.

Dans le précédent article : Backup, restauration – Part 6 J’ai évoqué la restauration PITR pour Point In Time Recovery. Je vous encourage vivement à mettre en place ce qui va suivre afin de réduire la perte de données en cas de modification accidentelle sur des enregistrements : Un drop table par exemple.

Pour la mettre en place il vous faut :

  • Une instance Postgres maître.
  • Archivage des WAL, externalisé de préférence.

Je ne vais pas revenir sur la mise en place de l’archivage, je l’ai déjà détaillé dans les précédents articles. Pour vous expliquer cette restauration je vais utiliser un scénario « catastrophe ».

Il est 12H30 et on vous informe qu’une table a été supprimée par erreur sur un serveur de production.

La réplication que vous avez mis en place ne vous est d’aucune aide car l’opération a été reportée sur le réplicat.

Remarque : Avec la version 9.4 il est possible d’avoir un réplicat avec du retard. Avec un peu de chance l’opération de suppression de la table n’est peut être pas encore réalisée sur le réplicat.

Par chance, vous effectuez un backup full toutes les nuits à 1H00 et vous avez mis en place l’archivage des journaux. Leur nettoyage se fait après le backup full grâce à pg_archivecleanup.

Pour être tranquille vous effectuez un checkpoint afin que les derniers journaux soient archivés. Ensuite vous stoppez votre instance Postgres et déplacez le répertoire (au cas où).

Vous restaurez les fichiers du backup full. Il ne vous reste plus qu’a configurer correctement la restauration via le fichier recovery.conf.

Celui-ci devra contenir le paramètre restore_command afin que Postgres récupére les journaux de transactions archivés.

Il devra également contenir un paramètre pour la cible de récupération, Si on ne le spécifie pas le moteur va rejouer les journaux de transaction dans leur totalité, jusqu’au « drop table » fatal. Il est possible de demander la restauration jusqu’à un point de restauration, une date ou un identifiant de transaction.

Pour approfondir : http://docs.postgresqlfr.org/current/recovery-target-settings.html

Revenons à notre scénario, imaginons que nous souhaitons revenir à la dernière transaction jouée avant le drop fatal. En grattant un peu, on peut utiliser l’outil  pg_xlogdump pour lire les journaux de transaction.

C’est un extrait du résultat de la commande, le première ligne indique un insert avec la transaction N° 1213547, la ligne ne dessous indique un commit. En revanche à la troisième ligne on est passé à la transaction 1213548 avec un lock suivi de plusieurs lignes indiquant un delete. Il s’agit du drop fatal.

On va donc revenir à la transaction N°1213547. Voici le contenu de mon fichier recovery.conf :

La directive recovery_target_inclusive indique au moteur s’il inclue la transaction correspondant au N°1213547 ou s’il s’arrête juste avant. Ainsi j’aurais pu spécifier un xid de 1213548  et un target_inclusive à « false » pour obtenir le même résultat.

Ensuite il suffit de redémarrer postgres, voici ce qu’on peut observer dans les logs :

On remarque que le moteur créée le répertoire des journaux de transaction, ensuite la ligne suivante est assez explicite : « starting point-in-time recovery to XID 1213547 ». Quelques lignes plus bas on remarque qu’il rejoue les journaux de transaction (« restored log file « 000000010000000300000065 » from archive »).

Il arrête la restauration jusqu’à la transaction spécifiée :

On remarque quelques lignes d’erreur correspondant à la sortie de rsync. Visiblement il cherche à copier plusieurs fichiers en « x.history ».  En regardant dans le répertoire d’archivage on constate que le moteur a créé un fichier 00000002.history contenant :

1       3/66000120      after transaction 1213547

Point important également, on constate que la numérotation des journaux de transaction a changée :

Le fichier « 000000010000000300000065 » correspond au wal lors du pg_basebackup, « 000000010000000300000066 » correspond au checkpoint que j’ai lancé après l’incident. Après la restauration on peut voir le fichier « 000000020000000300000066 ». Le huitième caractère est passé de 1 à 2.

En retournant dans les logs du moteur on peut lire la ligne suivante un peu plus bas : « selected new timeline ID: 2″En fait, lors de la restauration, Postgres créée une nouvelle timeline. C’est un concept que j’aborderai plus tard, en attendant je vous invite à voir cette présentation sur le fonctionnement des timeline après une restauration PIRT : https://wiki.postgresql.org/images/e/e5/FOSDEM2013-Timelines.pdf

Bien entendu comme tout système de sauvegarde vous devez jouer la procédure afin de valider qu’il y a pas eu d’erreur ou oubli.

 

Share

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *