Restauration, recover maximal avec Barman
Perdre le minimum de transactions validées
Erreur d'un administrateur, corruption d'un filesystem ou incident matériel...vous avez perdu votre cluster PostgreSQL. Il ne s'agit pas d'une erreur applicative, vous ne voulez pas faire revenir les bases en arrière. Le but va donc être de restituer le service en perdant un minimum de transactions validées et même, si possible, aucune.
Le cluster PostgreSQL 10 sur Debian 10 est sauvegardé via Barman 2.x selon la méthode de sauvegarde distante, le RPO (recovery point objective, perte de données maximale admissible) doit être proche de 0.
Tout d'abord, simulation d'incident :
-- serveur pgpr10
-- session utilisateur, postgres
psql
create table temoin(col timestamp);
CREATE TABLE
insert into temoin values(current_timestamp) returning *;
col
---------------------------
2018-02-14 04:22:10.13207
(1 ligne)
INSERT 0 1
\watch 1
...
mer. 14 févr. 2018 04:23:31 CET (chaque 1s)
col
----------------------------
2018-02-14 04:23:31.204303
(1 ligne)
...
-- incident majeur, root
pg_lsclusters
rm -fr /var/lib/postgresql/10/apptra001/*
-- dans la session de l'utilisateur, postgres
mer. 14 févr. 2018 11:12:23 CET (chaque 1s)
col
----------------------------
2018-02-14 11:12:23.404273
(1 ligne)
ATTENTION: arrêt de la connexion à cause de l'arrêt brutal d'un autre processus serveur
DéTAIL : Le postmaster a commandé à ce processus serveur d'annuler la transaction
courante et de quitter car un autre processus serveur a quitté anormalement
et qu'il existe probablement de la mémoire partagée corrompue.
ASTUCE : Dans un moment, vous devriez être capable de vous reconnecter à la base de
données et de relancer votre commande.
la connexion au serveur a été coupée de façon inattendue
Le serveur s'est peut-être arrêté anormalement avant ou durant le
traitement de la requête.
La connexion au serveur a été perdue. Tentative de réinitialisation : échec.
Au vu de l'incident, peut-être aurions-nous la possibilité d'agir via un utilitaire quelconque développé pour le type de filesystem sur lequel repose le cluster. Il faut toujours évaluer si une restauration est réellement nécessaire avant de se lancer. Nous allons ici supposer que nous ne disposons d'aucune solution en dehors d'une restauration depuis Barman :
-- serveur bapr, barman
barman recover --remote-ssh-command "ssh postgres@pgpr10" apptra001 latest /var/lib/postgresql/10/apptra001
...
Your PostgreSQL server has been successfully prepared for recovery!
-- serveur pgpr10, root
vi /var/lib/barman/10/apptra001/recovery.conf, ajout de standby_mode = on
# The 'barman-wal-restore' command is provided in the 'barman-cli' package
restore_command = 'barman-wal-restore -U barman bapr apptra001 %f %p'
standby_mode = on
pg_ctlcluster 10 apptra001 start
pg_lsclusters
Ver Cluster Port Status Owner Data directory Log file
10 apptra001 5432 online,recovery postgres /var/lib/postgresql/10/apptra001 /var/log/postgresql/postgresql-10-apptra001.log
tail -f /var/log/postgresql/postgresql-10-apptra001.log
2018-02-14 11:47:27.775 CET [1013] LOG: restauration du journal de transactions « 000000010000000000000007 » à partir de l'archive
2018-02-14 11:47:29.126 CET [1013] LOG: restauration du journal de transactions « 000000010000000000000008 » à partir de l'archive
ERROR: WAL file '000000010000000000000009' not found in server 'apptra001' (SSH host: 192.168.56.220)
ERROR: Remote 'barman get-wal' command has failed!
-- serveur pgpr10, postgres
psql
select max(col) from temoin;
max
----------------------------
2018-02-14 10:54:18.817031
(1 ligne)
La restauration et le recover se sont bien passés mais nous pouvons constater que nous n'avons travaillé qu'avec les WAL archivés (jusqu'au WAL 000000010000000000000008 inclus).
La dernière transaction dont nous disposons date de 10h54 alors que nous avons pu travailler jusque 11h12. C'est mieux que rien mais nous pouvons aller plus loin puisque nous disposons du WAL courant au moment de l'incident (ici le 000000010000000000000009) grâce au streaming WAL effectué vers Barman. Avec standby_mode à on, le cluster attend des informations de journalisation en mode recover comme le ferait un cluster de secours. Nous allons fournir manuellement ces informations en copiant le WAL qui était en cours de streaming dans le dossier pg_wal :
-- serveur bapr, barman
cd /var/lib/barman/apptra001/streaming
ls -ltr
total 16384
-rw------- 1 barman barman 16777216 févr. 14 11:12 000000010000000000000009.partial
scp 000000010000000000000009.partial postgres@pgpr10:/var/lib/postgresql/10/apptra001/pg_wal/000000010000000000000009
-- serveur pgpr10, root
vi /var/lib/barman/10/apptra001/recovery.conf, on ne garde que standby_mode=on
standby_mode = on
pg_ctlcluster 10 apptra001 restart
tail -f /var/log/postgresql/postgresql-10-apptra001.log
...
2018-02-14 12:13:54.734 CET [2697] ATTENTION: le fichier de restauration « recovery.conf » n'a spécifié ni primary_conninfo ni restore_command
2018-02-14 12:13:54.734 CET [2697] ASTUCE : Le serveur de la base de données va régulièrement interroger le sous-répertoire
pg_wal pour vérifier les fichiers placés ici.
-- serveur pgpr10, postgres
psql
select max(col) from temoin;
max
----------------------------
2018-02-14 11:12:23.404273
(1 ligne)
-- serveur pgpr10, root
mv /var/lib/postgresql/10/apptra001/recovery.conf /var/lib/postgresql/10/apptra001/recovery.done
mv /var/lib/postgresql/10/apptra001/postgresql.auto.conf.origin /var/lib/postgresql/10/apptra001/postgresql.auto.conf
pg_ctlcluster 10 apptra001 restart
pg_lsclusters
Ver Cluster Port Status Owner Data directory Log file1
10 apptra001 5432 online postgres /var/lib/postgresql/10/apptra001 /var/log/postgresql/postgresql-10-apptra001.log
tail -f /var/log/postgresql/postgresql-10-apptra001.log
...
2018-02-14 12:29:37.821 CET [3255] LOG: ré-exécution faite à 0/90FFC00
2018-02-14 12:29:37.821 CET [3255] LOG: la dernière transaction a eu lieu à 2018-02-14 11:12:23.404583+01 (moment de la journalisation)
2018-02-14 12:29:37.896 CET [3254] LOG: le système de bases de données est prêt pour accepter les connexions
-- serveur bapr, barman
barman receive-wal --create-slot apptra001
Creating physical replication slot 'barman' on server 'apptra001'
Replication slot 'barman' created
barman cron
Starting WAL archiving for server apptra001
Starting streaming archiver for server apptra001
barman check apptra001
...OK
11h12min23s : nous n'avons dans cet exemple perdu aucune transaction. En pratique, lorsque le streaming WAL vers Barman n'est pas effectué de manière synchrone, quelques transactions peuvent être perdues en fonction de la latence réseau, de la charge etc. Si aucune transaction ne doit être perdue, il est possible de réaliser le streaming WAL de manière synchrone mais cela peut présenter d'autres inconvénients en termes de disponibilité (il est conseillé d'avoir plusieurs destinations pour le streaming WAL dans ce cas) et de performance.
Après avoir constaté que tout est OK, rétablir l'archivage car Barman positionne archive_command=FALSE après une restauration afin d'éviter les confusions et les erreurs. Vous n'avez pas besoin de le faire manuellement car les fichiers de configuration originaux sont disponibles avec l'extension .origin.
Vérifier également que la sauvegarde est toujours opérationnelle au niveau de Barman, un barman check nom_cluster doit dans tous les cas être 100% OK avant de rendre la main aux utilisateurs.
Mise à jour : 14/02/2018