Restauration, PITR dans une timeline différente de celle du backup de base avec Barman

Une situation piégeuse

      La situation est la même que dans ce scenario de PITR, nous avons un environnement PostgreSQL 10 sur Debian 10 sauvegardé via Barman 2.x mais vous n'avez pas suivi mon conseil et vous ne disposez pas d'un backup au début de chaque timeline.
      Nous voulons toujours réaliser un PITR au 18/02/2018 20:00:00 :

-- serveur bapr, barman cd /var/lib/barman/apptra001/wals ls -ltR ./0000000600000000: ./0000000500000000: ./0000000400000000: ./0000000300000000: total 364 -rw------- 1 barman barman 46445 févr. 18 20:10 000000030000000000000014 ... -rw------- 1 barman barman 94531 févr. 18 19:20 000000030000000000000010 ./0000000200000000: ./0000000100000000: barman list-backup all apptra001 20180218T185648 - Sun Feb 18 18:56:52 2018 - Size: 23.0 MiB - WAL Size: 26.6 KiB apptra001 20180218T164738 - Sun Feb 18 16:47:41 2018 - Size: 22.7 MiB - WAL Size: 875.9 KiB barman show-backup apptra001 20180218T185648 ... Timeline : 2 ... barman show-backup apptra001 20180218T164738 ... Timeline : 1 ...


      La timeline à considérer est la 3 mais nous ne disposons pas de backup de base dans cette timeline.
      20180218T164738 a été réalisé dans la timeline 1 et 20180218T185648 dans la timeline 2.
      La première idée est souvent d'utiliser le backup le plus récent antérieur au point de recover choisi. 20180218T185648 semble donc un choix naturel mais attention :

-- serveur bapr, barman cp /var/lib/barman/apptra001/wals/00000003.history /tmp/00000003.history.gz gunzip /tmp/00000003.history.gz cat /tmp/00000003.history 1 0/10003568 before 2018-02-18 18:30:00.281841+01


      Les informations de journalisation doivent absolument être appliquées de manière séquentielle. Lors d'un recover, il est impossible de sauter des informations de journalisation ou de revenir en arrière par exemple.
      La timeline 3 est issue d'un PITR effectué dans la timeline 1. Cela signifie que faire un PITR dans la timeline 3 implique d'utiliser un backup de la timeline 3 effectué avant le point de recover souhaité ou encore un backup de la timeline 1 effectué avant l'embranchement correspondant au PITR effectué le 18/02/2018 à 18h30.
      Restaurer un backup de la timeline 2 puis effectuer un recover dans cette timeline nous conduirait à un cul-de-sac. Nous allons donc utiliser le backup effectué dans la timeline 1 :

-- serveur papr10, root pg_ctlcluster 10 apptra001 stop rm -fr /var/lib/postgresql/10/apptra001/* -- serveur bapr, barman barman recover --target-tli 3 --target-time "2018-02-18 20:00:00" --remote-ssh-command "ssh postgres@pgpr10" apptra001 20180218T164738 /var/lib/postgresql/10/apptra001 ERROR: You cannot specify multiple targets for the recovery operation barman recover --target-time "2018-02-18 20:00:00" --remote-ssh-command "ssh postgres@pgpr10" apptra001 20180218T164738 /var/lib/postgresql/10/apptra001 ... Your PostgreSQL server has been successfully prepared for recovery -- serveur papr10, root cd /var/lib/postgresql/10/apptra001/ vi recovery.conf ajout de recovery_target_timeline = 3 # The 'barman-wal-restore' command is provided in the 'barman-cli' package restore_command = 'barman-wal-restore -U barman bapr apptra001 %f %p' recovery_target_time = '2018-02-18 20:00:00' recovery_target_timeline = 3 pg_ctlcluster 10 apptra001 start tail -f /var/log/postgresql/postgresql-10-apptra001.log ... 2018-02-19 11:40:48.774 CET [1105] LOG: restauration du journal de transactions « 00000001000000000000000F » à partir de l'archive 2018-02-19 11:40:49.682 CET [1105] LOG: restauration du journal de transactions « 000000030000000000000010 » à partir de l'archive 2018-02-19 11:40:50.602 CET [1105] LOG: restauration du journal de transactions « 000000030000000000000011 » à partir de l'archive 2018-02-19 11:40:51.626 CET [1105] LOG: restauration du journal de transactions « 000000030000000000000012 » à partir de l'archive 2018-02-19 11:40:52.635 CET [1105] LOG: restauration du journal de transactions « 000000030000000000000013 » à partir de l'archive 2018-02-19 11:40:52.714 CET [1105] LOG: arrêt de la restauration avant validation de la transaction 8287, 2018-02-18 20:00:01.725972+01 2018-02-19 11:40:52.714 CET [1105] LOG: restauration en pause 2018-02-19 11:40:52.714 CET [1105] ASTUCE : Exécuter pg_wal_replay_resume() pour continuer. -- serveur papr10, postgres select max(c1) from temoin; max --------------------------- 2018-02-18 19:59:59.93382 (1 ligne) select pg_wal_replay_resume(); pg_wal_replay_resume ---------------------- (1 ligne) select max(c1) from temoin; max --------------------------- 2018-02-18 19:59:59.93382 (1 ligne) -- serveur papr10, root cd /var/lib/postgresql/10/apptra001/ mv postgresql.auto.conf.origin postgresql.auto.conf pg_ctlcluster 10 apptra001 reload -- serveur bapr, barman barman receive-wal --create-slot apptra001 Creating physical replication slot 'barman' on server 'apptra001' Replication slot 'barman' created barman receive-wal --reset apptra001 Starting receive-wal for server apptra001 Resetting receive-wal directory status Removing status file /var/lib/barman/apptra001/streaming/000000060000000000000016.partial barman cron Starting WAL archiving for server apptra001 Starting streaming archiver for server apptra001 barman check apptra001 ...OK barman backup apptra001


      Nous aurions pu nous tromper de backup de base à utiliser mais il y a un second piège à éviter. Barman ne permet pas de tout automatiser dans le cas d'un PITR à effectuer dans une timeline différente du backup de base. La commande "barman recover" accepte certes de positionner une timeline via --target-tli mais, en version 2.3, il est impossible de positionner 2 informations de targets alors que nous aurions ici besoin de --target-tli et --target-time.
      Il faut par conséquent impérativement apporter l'information manquante "recovery_target_timeline" manuellement dans le fichier recovery.conf avant de relancer le cluster sous peine de suivre la timeline 1, de dépasser le point d'embranchement vers la timeline 3 et de ne pas obtenir le résultat souhaité.
      Si le fichier recovery.conf est correctement renseigné alors PostgreSQL accomplit très bien ce que nous souhaitons. Il suit la timeline 1 jusqu'à l'embranchement vers la timeline 3 puis la timeline 3 jusqu'au point de recover.
      La suite ne diffère pas de ce qui était indiqué dans ce scenario de PITR. Nous effectuons notamment une première sauvegarde dans la nouvelle timeline. PostgreSQL est bien capable dans une session de restauration de traverser les timelines mais cela ne veut pas dire que cela soit souhaitable. Il vaut mieux faire le plus simple possible lorsqu'il s'agit de restaurer.
      Dernier point, le PITR a ici été effectué en supprimant le cluster initial et en réutilisant le même filesystem mais je conseille à nouveau fortement d'utiliser un serveur et un stockage différents lorsque c'est possible.

Mise à jour : 19/02/2018