PostgreSQL maintient en permanence des journaux WAL
(write ahead log) dans le sous-répertoire
pg_wal/
du répertoire de données du cluster. Ces journaux
enregistrent chaque modification effectuée sur les fichiers de données des
bases. Ils existent principalement pour se prémunir des suites d'un
arrêt brutal : si le système s'arrête brutalement, la base de données
peut être restaurée dans un état cohérent en
« rejouant » les entrées des journaux enregistrées depuis le dernier
point de vérification. Néanmoins, l'existence de ces journaux rend possible
l'utilisation d'une troisième stratégie pour la sauvegarde des bases de
données : la combinaison d'une sauvegarde de niveau système de
fichiers avec la sauvegarde des fichiers WAL. Si la récupération est
nécessaire, la sauvegarde des fichiers est restaurée, puis les fichiers WAL sauvegardés
sont rejoués pour amener la sauvegarde jusqu'à la date
actuelle. Cette approche est plus complexe à administrer que toutes les
autres approches mais elle apporte des bénéfices significatifs :
Il n'est pas nécessaire de disposer d'une sauvegarde des fichiers parfaitement cohérente comme point de départ. Toute incohérence dans la sauvegarde est corrigée par la ré-exécution des journaux (ceci n'est pas significativement différent de ce qu'il se passe lors d'une récupération après un arrêt brutal). La fonctionnalité d'image du système de fichiers n'est alors pas nécessaire, tar ou tout autre outil d'archivage est suffisant.
Puisqu'une longue séquence de fichiers WAL peut être assemblée pour être rejouée, une sauvegarde continue est obtenue en continuant simplement à archiver les fichiers WAL. C'est particulièrement intéressant pour les grosses bases de données dont une sauvegarde complète fréquente est difficilement réalisable.
Les entrées WAL ne doivent pas obligatoirement être rejouées intégralement. La ré-exécution peut être stoppée en tout point, tout en garantissant une image cohérente de la base de données telle qu'elle était à ce moment-là. Ainsi, cette technique autorise la récupération d'un instantané (PITR) : il est possible de restaurer l'état de la base de données telle qu'elle était en tout point dans le temps depuis la dernière sauvegarde de base.
Si la série de fichiers WAL est fournie en continu à une autre machine chargée avec le même fichier de sauvegarde de base, on obtient un système « de reprise intermédiaire » (warm standby) : à tout moment, la deuxième machine peut être montée et disposer d'une copie quasi-complète de la base de données.
pg_dump et pg_dumpall ne font pas de sauvegardes au niveau système de fichiers. Ce type de sauvegarde est qualifié de logique et ne contiennent pas suffisamment d'informations pour permettre le rejeu des journaux de transactions.
Tout comme la technique de sauvegarde standard du système de fichiers, cette méthode ne supporte que la restauration d'un cluster de bases de données complet, pas d'un sous-ensemble. De plus, un espace d'archivage important est requis : la sauvegarde de la base peut être volumineuse et un système très utilisé engendre un trafic WAL à archiver de plusieurs Mo. Malgré tout, c'est la technique de sauvegarde préférée dans de nombreuses situations où une haute fiabilité est requise.
Une récupération fructueuse à partir de l'archivage continu (aussi appelé « sauvegarde à chaud » par certains vendeurs de SGBD) nécessite une séquence ininterrompue de fichiers WAL archivés qui s'étend au moins jusqu'au point de départ de la sauvegarde. Pour commencer, il faut configurer et tester la procédure d'archivage des journaux WAL avant d'effectuer la première sauvegarde de base. C'est pourquoi la suite du document commence par présenter les mécanismes d'archivage des fichiers WAL.
Au sens abstrait, un système PostgreSQL fonctionnel produit une séquence infinie d'enregistrements WAL. Le système divise physiquement cette séquence en fichiers de segment WAL de 16 Mo chacun (en général, mais cette taille peut être modifiée lors de la construction de PostgreSQL). Les fichiers segment reçoivent des noms numériques pour refléter leur position dans la séquence abstraite des WAL. Lorsque le système n'utilise pas l'archivage des WAL, il ne crée que quelques fichiers segment, qu'il « recycle » en renommant les fichiers devenus inutiles. Un fichier segment dont le contenu précède le dernier point de vérification est supposé inutile et peut être recyclé.
Lors de l'archivage des données WAL, le contenu de
chaque fichier segment doit être capturé dès qu'il est rempli pour
sauvegarder les données ailleurs avant son recyclage.
En fonction de l'application et du matériel disponible,
« sauvegarder les données ailleurs » peut se faire de plusieurs
façons : les fichiers segment peuvent être copiés dans un répertoire
NFS monté sur une autre machine, être écrits sur une cartouche (après
s'être assuré qu'il existe un moyen d'identifier le nom d'origine de chaque
fichier) ou être groupés pour gravure sur un CD, ou toute autre chose.
Pour fournir autant de flexibilité que possible à l'administrateur de la
base de données, PostgreSQL essaie de ne faire aucune
supposition sur la façon dont l'archivage est réalisé. À la place,
PostgreSQL permet de préciser la commande
shell à exécuter pour copier le fichier segment complet à l'endroit
désiré. La commande peut être aussi simple qu'un
cp
ou impliquer un shell complexe --
c'est l'utilisateur qui décide.
Pour activer l'archivage des journaux de transaction, on positionne le
paramètre de configuration wal_level à
replica
ou supérieur,
archive_mode à on
,
et on précise la commande shell à utiliser dans le paramètre
archive_command de la configuration. En fait, ces
paramètres seront toujours placés dans le fichier
postgresql.conf
. Dans cette chaîne, un
%p
est remplacé par le chemin absolu de
l'archive alors qu'un %f
n'est remplacé que par le
nom du fichier. (Le nom du chemin est relatif au répertoire de travail du
serveur, c'est-à-dire le répertoire des données du cluster.)
%%
est utilisé pour écrire le
caractère %
dans la commande. La commande la plus
simple ressemble à :
archive_command = 'test ! -f /mnt/serveur/repertoire_archive/%f && cp %p /mnt/serveur/repertoire_archive/%f' # Unix archive_command = 'copy "%p" "C:\\serveur\\repertoire_archive\\%f"' # Windows
qui copie les segments WAL archivables dans le répertoire
/mnt/serveur/repertoire_archive
. (Ceci est un exemple, pas
une recommandation, et peut ne pas fonctionner sur toutes les
plateformes.) Après le remplacement des paramètres %p
et %f
, la commande réellement exécutée peut ressembler
à :
test ! -f /mnt/serveur/repertoire_archive/00000001000000A900000065 && cp pg_wal/00000001000000A900000065 /mnt/serveur/repertoire_archive/00000001000000A900000065
Une commande similaire est produite pour chaque nouveau fichier à archiver.
La commande d'archivage est exécutée sous l'identité de l'utilisateur propriétaire du serveur PostgreSQL. La série de fichiers WAL en cours d'archivage contient absolument tout ce qui se trouve dans la base de données, il convient donc de s'assurer que les données archivées sont protégées des autres utilisateurs ; on peut, par exemple, archiver dans un répertoire sur lequel les droits de lecture ne sont positionnés ni pour le groupe ni pour le reste du monde.
Il est important que la commande d'archivage ne renvoie le code de sortie zéro que si, et seulement si, l'exécution a réussi. En obtenant un résultat zéro, PostgreSQL suppose que le fichier segment WAL a été archivé avec succès et qu'il peut le supprimer ou le recycler. Un statut différent de zéro indique à PostgreSQL que le fichier n'a pas été archivé ; il essaie alors périodiquement jusqu'à la réussite de l'archivage.
La commande d'archivage doit, en général, être conçue pour refuser d'écraser tout fichier archive qui existe déjà. C'est une fonctionnalité de sécurité importante pour préserver l'intégrité de l'archive dans le cas d'une erreur de l'administrateur (comme l'envoi de la sortie de deux serveurs différents dans le même répertoire d'archivage).
Il est conseillé de tester la commande d'archivage proposée pour
s'assurer, qu'en effet, elle n'écrase pas un fichier existant, et
qu'elle retourne un statut différent de zéro dans ce cas.
La commande pour Unix en exemple ci-dessus le garantit en incluant
une étape test
séparée. Sur certaines plateformes
Unix, la commande cp
dispose d'une option, comme
-i
pouvant être utilisé pour faire la même chose,
mais en moins verbeux. Cependant, vous ne devriez pas vous baser
là-dessus sans vous assurer que le code de sortie renvoyé est le bon.
(en particulier, la commande cp
de GNU renvoie
un code zéro quand -i
est utilisé et que le fichier
cible existe déjà, ce qui n'est pas le
comportement désiré.)
Lors de la conception de la configuration d'archivage, il faut
considérer ce qui peut se produire si la commande d'archivage échoue de façon
répétée, que ce soit parce qu'une intervention de l'opérateur s'avère nécessaire ou
par manque d'espace dans le répertoire d'archivage.
Ceci peut arriver, par exemple, lors de l'écriture sur une cartouche sans changeur
automatique ; quand la cartouche est pleine, rien ne peut être
archivé tant que la cassette n'est pas changée.
Toute erreur ou requête à un opérateur humain doit être rapportée de façon
appropriée pour que la situation puisse être résolue
rapidement. Le répertoire pg_wal/
continue à se remplir
de fichiers de segment WAL jusqu'à la résolution de la situation.
(Si le système de fichiers contenant pg_wal/
se
remplit, PostgreSQL s'arrête en mode PANIC.
Aucune transaction validée n'est perdue mais la base de données est
inaccessible tant que de l'espace n'a pas été libéré.)
La vitesse de la commande d'archivage n'est pas importante, tant qu'elle
suit le rythme de génération des données WAL du serveur. Les
opérations normales continuent même si le processus d'archivage est un peu
plus lent. Si l'archivage est significativement plus lent, alors la
quantité de données qui peut être perdue croît. Cela signifie
aussi que le répertoire pg_wal/
contient un grand nombre
de fichiers segment non archivés, qui peuvent finir par
dépasser l'espace disque disponible. Il est conseillé de surveiller
le processus d'archivage pour s'assurer que tout fonctionne
normalement.
Lors de l'écriture de la commande d'archivage, il faut garder à l'esprit que les
noms de fichier à archiver peuvent contenir jusqu'à 64 caractères et
être composés de toute combinaison de lettres ASCII, de chiffres et de points.
Il n'est pas nécessaire de conserver le chemin relatif original
(%p
) mais il est nécessaire de se rappeler du nom du fichier
(%f
).
Bien que l'archivage WAL autorise à restaurer toute
modification réalisée sur les données de la base, il ne restaure pas les modifications
effectuées sur les fichiers de configuration (c'est-à-dire
postgresql.conf
, pg_hba.conf
et
pg_ident.conf
) car ceux-ci sont édités manuellement
et non au travers d'opérations SQL. Il est souhaitable de conserver les
fichiers de configuration à un endroit où ils sont sauvegardés par les
procédures standard de sauvegarde du système de fichiers. Voir la
Section 19.2 pour savoir comment
modifier l'emplacement des fichiers de configuration.
La commande d'archivage n'est appelée que sur les segments WAL complets.
Du coup, si le serveur engendre peu de trafic WAL (ou qu'il y a des périodes
de calme où le trafic WAL est léger), il peut y avoir un long délai
entre la fin d'une transaction et son enregistrement sûr dans le stockage
d'archive. Pour placer une limite sur l'ancienneté des données archivées,
on configure archive_timeout qui force le
serveur à changer de fichier segment WAL passé ce délai. Les
fichiers archivés lors d'un tel forçage ont toujours
la même taille que les fichiers complets. Il est donc déconseillé de configurer
un délai archive_timeout
trop court -- cela fait
grossir anormalement le stockage. Une minute pour archive_timeout
est généralement raisonnable.
De plus, le changement d'un segment peut être forcé manuellement avec
pg_switch_wal
. Cela permet de s'assurer qu'une
transaction tout juste terminée est archivée aussi vite que possible.
D'autres fonctions utilitaires relatives à la gestion des WAL sont
disponibles dans Tableau 9.79.
Quand wal_level
est configuré à
minimal
, certaines commandes SQL sont optimisées pour
éviter la journalisation des transactions, de la façon décrite dans
Section 14.4.7. Si l'archivage ou la réplication en flux
est activé lors de
l'exécution d'une de ces instructions, les journaux de transaction ne
contiennent pas suffisamment d'informations pour une récupération via les
archives. (La récupération après un arrêt brutal n'est pas affectée.)
Pour cette raison, wal_level
ne peut être
modifié qu'au lancement du serveur. Néanmoins,
archive_command
peut être modifié par
rechargement du fichier de configuration. Pour arrêter
temporairement l'archivage, on peut placer une
chaîne vide (''
) pour
archive_command
. Les journaux de transaction sont alors
accumulés dans pg_wal/
jusqu'au rétablissement
d'un paramètre archive_command
fonctionnel.
La manière la plus simple pour effectuer une sauvegarde d'utiliser l'outil pg_basebackup. Il peut créer une sauvegarde de base soit sous la forme de fichiers standards, soit dans une archive tar. Pour les cas plus complexes, il est possible de réaliser une sauvegarde de base en utilisant l'API bas niveau (voir Section 25.3.3).
La durée d'une sauvegarde de base n'est pas toujours un critère déterminant. Toutefois,
si vous exploitez votre server avec l'option full_page_writes
désactivée, vous constaterez une baisse des performances lorsque la sauvegarde
est effectuée car l'option full_page_writes
est
activée de force pendant les opérations de sauvegarde.
Pour utiliser une sauvegarde, vous devez conserver tous les segments WAL générés
pendant et après la sauvegarde des fichiers. Pour vous aider dans cette tache,
le processus de sauvegarde crée un fichier historique de
sauvegarde qui est immédiatement enregistré dans la zone
d'archivage des WAL. Le nom de ce fichier reprend le nom du premier fichier
WAL que vous devez conserver. Par exemple, si le premier fichier WAL à garder
est 0000000100001234000055CD
, alors le fichier
historique de sauvegarde sera nommé de la manière suivante
0000000100001234000055CD.007C9330.backup
. (La seconde
partie du nom de fichier indique la position exacte à l'intérieur du fichier
WAL. Cette information peut être ignorée). Une fois que vous avez
archivé avec précaution la sauvegarde de base et les fichiers WAL générés
pendant la sauvegarde (tel qu'indiqué par le fichier historique de sauvegarde),
tous les fichiers WAL antérieurs ne sont plus nécessaires pour restaurer
votre sauvegarde de base. Ils peuvent être supprimés. Toutefois il est conseillé
de conserver plusieurs groupes de sauvegardes pour être absolument certain de
récupérer vos données.
Le fichier historique de sauvegarde est un simple fichier texte. Il contient le label que vous avez attribué à l'opération pg_basebackup, ainsi que les dates de début, de fin et la liste des segments WAL de la sauvegarde. Si vous avez utilisé le label pour identifier le fichier de sauvegarde associé, alors le fichier historique vous permet de savoir quel fichier de sauvegarde vous devez utiliser pour la restauration.
Puisque vous devez archiver tous les fichiers WAL depuis votre dernière sauvegarde de base, l'intervalle entre deux sauvegardes de base doit être déterminé en fonction de l'espace de stockage que vous avez alloué pour l'archivage des fichiers WAL. Vous devez également prendre en compte le temps de restauration (Le système devra rejouer tous les segments WAL, cela prendra un certain temps si la sauvegarde de base est ancienne).
La procédure pour créer une sauvegarde de base en utilisant l'API bas niveau contient plus d'étapes que la méthode pg_basebackup mais elle est relativement simple. Il est très important que ces étapes soit exécutées séquentiellement et de vérifier que chaque étape s'est déroulée correctement avant de passer à la suivante.
Les sauvegardes bas niveau peuvent être réalisées de façon exclusive ou non-exclusive. La méthode non-exclusive est recommandée alors que l'exclusive est obsolète et sera à la longue supprimée.
Une sauvegarde non-exclusive bas niveau permet à d'autres sauvegardes concurrentes d'être lancées (à la fois celles utilisant la même API et celles utilisant pg_basebackup).
S'assurer que l'archivage WAL est activé et fonctionnel.
Se connecter au serveur (peu importe la base) en tant qu'utilisateur ayant les droits d'exécuter pg_start_backup (superutilisateur, ou un utilisateur ayant été autorisé à EXECUTE la fonction) et lancer la commande :
SELECT pg_start_backup('label', false, false);
où label
est une chaîne utilisée pour identifier de
façon unique l'opération de sauvegarde. La connexion
appelant pg_start_backup
doit être maintenue jusqu'à la fin de
la sauvegarde, ou la sauvegarde sera automatiquement avortée.
Par défaut, pg_start_backup
peut prendre beaucoup de temps
pour arriver à son terme.
Ceci est dû au fait qu'il réalise un
point de vérification (checkpoint),
et que les entrées/sorties pour l'établissement
de ce point de vérification seront réparties sur une grande durée,
par défaut la moitié de l'intervalle entre deux points de
vérification (voir le paramètre de configuration
checkpoint_completion_target). Habituellement,
ce comportement est appréciable, car il minimise l'impact du traitement
des requêtes. Pour commencer la sauvegarde dès que possible, changer le
second paramètre à true
, ce qui exécutera un
checkpoint immédiat en utilisant autant d'entrées/sorties disque que
disponible.
Le troisième paramètre étant false
signifie que
pg_start_backup
initiera une sauvegarde de base non-exclusive.
Effectuer la sauvegarde à l'aide de tout outil de sauvegarde du système de fichiers, tel tar ou cpio (mais ni pg_dump ni pg_dumpall). Il n'est ni nécessaire ni désirable de stopper les opérations normales de la base de données pour cela. Voir la section Section 25.3.3.3 pour les considérations à prendre en compte durant cette sauvegarde.
Dans la même connexion que précédemment, lancer la commande :
SELECT * FROM pg_stop_backup(false, true);
Cela met fin au processus de sauvegarde. Sur un serveur primaire, cela
réalise aussi une bascule automatique au prochain segment de journal de
transactions. Sur un serveur secondaire (standby), il n'est pas possible
de basculer automatiquement les segments des journaux de transactions,
donc vous pourriez vouloir utiliser pg_switch_wal
sur le primaire pour réaliser une bascule manuelle. Cette bascule est
nécessaire pour permettre au dernier fichier de segment WAL écrit pendant
la sauvegarde d'être immédiatement archivable.
La fonction pg_stop_backup
retournera une ligne avec
trois valeurs. Le second de ces champs devrait être écrit dans un fichier
nommé backup_label
dans le répertoire racine de la
sauvegarde. Le troisième champ devrait être écrit dans un fichier nommé
tablespace_map
sauf si le champ est vide. Ces
fichiers sont vitaux pour le fonctionnement de la sauvegarde et doivent
être écrits octet par octet sans modification, ce qui nécessite de les
ouvrir en mode binaire.
Une fois que les fichiers de segment WAL utilisés lors de la sauvegarde
sont archivés, c'est terminé. Le fichier identifié par le résultat de
pg_stop_backup
est le dernier segment nécessaire
pour produire un jeu complet de fichiers de sauvegarde. Sur un serveur
primaire, si archive_mode
est activé et que le
paramètre wait_for_archive
est activé (valeur
true
), pg_stop_backup
ne rend pas
la main avant que le dernier segment n'ait été archivé. Sur un standby,
le paramètre archive_mode
doit valoir
always
pour que la fonction
pg_stop_backup
attende. L'archivage de ces fichiers
est automatique puisque
archive_command
est déjà configuré. Dans la plupart des
cas, c'est rapide, mais il est conseillé de surveiller le système d'archivage pour
s'assurer qu'il n'y a pas de retard. Si le processus d'archivage a pris du retard
en raison d'échecs de la commande d'archivage, il continuera d'essayer jusqu'à ce que
l'archivage réussisse et que la sauvegarde soit complète. Pour
positionner une limite au temps d'exécution de pg_stop_backup
,
il faut positionner statement_timeout
à une valeur
appropriée, mais il faut noter que si
pg_stop_backup
est interrompu à cause de cette configuration, la sauvegarde
peut ne pas être correcte.
Si le processus de sauvegarde surveille et s'assure que tous les fichiers
de segment WAL nécessaires à la sauvegarde soient archivés avec succès,
le paramètre wait_for_archive
(positionné à true par
défaut), peut être positionné à
false pour que pg_stop_backup
renvoie la main dès que
l'enregistrement de fin de sauvegarde est écrit dans le WAL. Par défaut,
pg_stop_backup
attendra jusqu'à ce que tous les WAL
aient été archivés, ce qui peut prendre un certain temps. Cette option
doit être utilisée avec précaution : si l'archivage des WAL n'est pas
supervisé correctement, alors la sauvegarde pourrait ne pas inclure tous
les fichiers WAL et serait donc incomplète et impossible à restaurer.
Le procédé pour une sauvegarde exclusive est majoritairement le même que pour la non-exclusive, mais il diffère en quelques étapes clés. Ce type de sauvegarde peut seulement être réalisé sur un serveur primaire et ne permet pas des sauvegardes concurrentes. Avant la version 9.6 de PostgreSQL, il s'agissait de la seule méthode bas niveau disponible, mais il est maintenant recommandé que tous les utilisateurs mettent à jour leurs scripts pour utiliser une sauvegarde non-exclusive si possible.
S'assurer que l'archivage des WAL est activé et fonctionnel.
Se connecter au serveur (peu importe la base) en tant qu'utilisateur ayant les droits d'exécuter pg_start_backup (superutilisateur, ou un utilisateur ayant le droit EXECUTE sur cette fonction) et lancer la commande :
SELECT pg_start_backup('label');
où label
est une chaîne utilisée pour identifier de
façon unique l'opération de sauvegarde.
pg_start_backup
crée un fichier de label
de sauvegarde nommé backup_label
dans le
répertoire du cluster. Ce fichier contient les informations de la
sauvegarde, ceci incluant le moment du démarrage et le label. La fonction
crée aussi un fichier tablespace map, appelé
tablespace_map
, dans le répertoire principal des
données avec des informations sur les liens symboliques des tablespaces
contenus dans pg_tblspc
si au moins un lien est
présent. Ces fichiers sont critiques à l'intégrité de la sauvegarde, vous
devez vous assurer de leur restauration.
Par défaut, pg_start_backup
peut prendre beaucoup de temps
pour arriver à son terme. Ceci est dû au fait qu'il réalise un
point de vérification (checkpoint),
et que les entrées/sorties pour l'établissement
de ce point de vérification seront réparties sur une grande durée,
par défaut la moitié de l'intervalle entre deux points de
vérification (voir le paramètre de configuration
checkpoint_completion_target). Habituellement,
ce comportement est appréciable, car il minimise l'impact du traitement
des requêtes. Pour commencer la sauvegarde aussi rapidement
que possible, utiliser :
SELECT pg_start_backup('label', true);
Cela force l'exécution du point de vérification aussi rapidement que possible.
Effectuer la sauvegarde à l'aide de tout outil de sauvegarde du système de fichiers, tel tar ou cpio (mais ni pg_dump ni pg_dumpall). Il n'est ni nécessaire ni désirable de stopper les opérations normales de la base de données pour cela. Voir la section Section 25.3.3.3 pour les considérations à prendre en compte durant cette sauvegarde.
Notez que, si le serveur s'arrête brutalement lors de la sauvegarde, il
pourrait ne pas être possible de recommencer tant que le fichier
backup_label
ne soit manuellement supprimée du
répertoire PGDATA
.
Se connecter à nouveau à la base de données en tant qu'utilisateur ayant le droit d'exécuter pg_stop_backup (superutilisateur, ou un utilisateur ayant le droit EXECUTE sur cette fonction) et lancer la commande :
SELECT pg_stop_backup();
Cette fonction met fin au processus de sauvegarde et réalise une bascule automatique vers le prochain segment WAL. Cette bascule est nécessaire pour permettre au dernier fichier de segment WAL écrit pendant la sauvegarde d'être immédiatement archivable.
Une fois que les fichiers des segments WAL utilisés lors de la sauvegarde
sont archivés, c'est terminé. Le fichier identifié par le résultat de
pg_stop_backup
est le dernier segment nécessaire pour produire
un jeu complet de fichiers de backup.
Si archive_mode
est activé,
pg_stop_backup
ne rend pas la main avant que le dernier segment
n'ait été archivé. L'archivage de ces fichiers est automatique puisque
archive_command
est configuré. Dans la plupart des
cas, c'est rapide, mais il est conseillé de surveiller le système d'archivage pour
s'assurer qu'il n'y a pas de retard. Si le processus d'archivage a pris du retard
en raison d'échecs de la commande d'archivage, il continuera d'essayer jusqu'à ce que
l'archive réussisse et que le backup soit complet. Pour
positionner une limite au temps d'exécution de pg_stop_backup
,
il faut positionner statement_timeout
à une valeur
appropriée, mais il faut noter que si
pg_stop_backup
est interrompu du fait de cette
configuration, la sauvegarde peut ne pas être correcte.
Certains outils de sauvegarde de fichiers émettent des messages d'avertissement ou d'erreur si les fichiers qu'ils essaient de copier sont modifiés au cours de la copie. Cette situation, normale lors de la sauvegarde d'une base active, ne doit pas être considérée comme une erreur ; il suffit de s'assurer que ces messages puissent être distingués des autres messages. Certaines versions de rsync, par exemple, renvoient un code de sortie distinct en cas de « disparition de fichiers source ». Il est possible d'écrire un script qui considère ce code de sortie comme normal.
De plus, certaines versions de GNU tar
retournent un code d'erreur qu'on peut confondre avec une erreur fatale si
le fichier a été tronqué pendant sa copie par
tar. Heureusement, les versions 1.16 et
suivantes de GNU tar retournent 1 si le fichier
a été modifié pendant la sauvegarde et 2 pour les autres erreurs. Avec GNU
tar version 1.23 et les versions ultérieures,
vous pouvez utiliser les options d'avertissement --warning=no-file-changed
--warning=no-file-removed
pour cacher les messages d'avertissement
en relation.
La sauvegarde doit inclure tous les fichiers du répertoire
du groupe de bases de données
(/usr/local/pgsql/data
, par exemple). Si des
tablespaces
qui ne se trouvent pas dans ce répertoire sont utilisés, il ne faut pas
oublier de les inclure (et s'assurer également que la sauvegarde archive les liens
symboliques comme des liens, sans quoi la restauration va corrompre les
tablespaces).
Néanmoins, les fichiers du sous-répertoire
pg_wal/
,
contenu dans le répertoire du cluster, devraient être omis. Ce léger
ajustement permet de réduire le risque d'erreurs lors de la restauration.
C'est facile à réaliser si pg_wal/
est un lien
symbolique vers quelque endroit extérieur au répertoire du cluster,
ce qui est toutefois une configuration courante, pour des raisons de
performance. Il peut être intéressant d'exclure postmaster.pid
et postmaster.opts
, qui enregistrent des
informations sur le postmaster en cours
d'exécution, mais pas sur le postmaster
qui va utiliser cette sauvegarde. De plus, ces fichiers peuvent poser
problème à pg_ctl.
C'est souvent une bonne idée d'omettre de la sauvegarde les fichiers provenant
du répertoire pg_replslot/
de l'instance, pour que les
slots de réplication existant sur le maître ne deviennent pas partie intégrante
de la sauvegarde. Dans le cas contraire, l'utilisation de la sauvegarde pour
créer un esclave pourrait résulter en une rétention infinie des journaux de
transactions sur l'esclave et aussi de la fragmentation sur le maître si les
messages retour d'un esclave en Hot Standby sont activés, parce que les clients
qui utilisent ces slots de réplication se connecteront toujours et mettront à
jour les slots sur le maître et non pas sur l'esclave. Même si la sauvegarde a
pour but d'être utilisée pour la création d'un nouveau maître, copier les slots
de réplication n'est pas un comportement attendu car il n'a pas de raison d'être,
le contenu de ces slots sera très probablement obsolète au moment où le nouveau
maître sera en ligne.
Le contenu des répertoires pg_dynshmem/
,
pg_notify/
, pg_serial/
,
pg_snapshots/
, pg_stat_tmp/
, et
pg_subtrans/
(mais pas les répertoires eux-même)
peuvent être exclu de la sauvegarde puisqu'ils seront réinitialisés au
démarrage du postmaster. Si stats_temp_directory est
positionné et qu'il pointe dans un sous répertoire du répertoire de données
alors le contenu de ce répertoire peut également être exclu.
N'importe quel fichier ou répertoire commençant par
pgsql_tmp
peut être exclu de la sauvegarde. Ces
fichiers sont supprimé au démarrage du postmaster et les répertoires seront
recréés si nécessaire.
Le fichier de label de la sauvegarde inclut la
chaîne de label passée à pg_start_backup
, l'heure à
laquelle pg_start_backup
a été exécuté et le nom du
fichier WAL initial. En cas de confusion, il est ainsi possible de
regarder dans le fichier sauvegarde et de déterminer avec précision de
quelle session de sauvegarde provient ce fichier. Le fichier des
tablespaces inclut les noms des liens symboliques s'ils existent dans le
répertoire pg_tblspc/
et le chemin complet de chaque
lien symbolique. Néanmoins, ces fichiers n'existent pas uniquement pour
vous informer. Leurs présences et contenus sont critiques au bon
déroulement du processus de restauration.
Il est aussi possible de faire une sauvegarde alors que le serveur est
arrêté. Dans ce cas, pg_start_backup
et
pg_stop_backup
ne peuvent pas être
utilisées. L'utilisateur doit alors se débrouiller pour identifier les
fichiers de sauvegarde et déterminer jusqu'où remonter avec les fichiers
WAL associés. Il est généralement préférable de
suivre la procédure d'archivage continu décrite ci-dessus.
Le pire est arrivé et il faut maintenant repartir d'une sauvegarde. Voici la procédure :
Arrêter le serveur s'il est en cours d'exécution.
Si la place nécessaire est disponible, copier le répertoire complet de
données du cluster et tous les tablespaces
dans un emplacement temporaire en prévision d'un éventuel besoin
ultérieur. Cette précaution nécessite qu'un espace suffisant sur le
système soit disponible pour contenir deux copies de la base de données
existante. S'il n'y a pas assez de place disponible, il faut au minimum
copier le contenu du sous-répertoire pg_wal
du
répertoire des données du cluster car il peut contenir des journaux
qui n'ont pas été archivés avant l'arrêt du serveur.
Effacer tous les fichiers et sous-répertoires existant sous le répertoire des données du cluster et sous les répertoires racines des tablespaces.
Restaurer les fichiers de la base de données à partir de la
sauvegarde des fichiers. Il faut veiller à ce qu'ils soient restaurés avec le bon
propriétaire (l'utilisateur système de la base de données, et non pas
root
!) et avec les bons droits. Si des
tablespaces sont utilisés, il faut
s'assurer que les liens symboliques dans
pg_tblspc/
ont été correctement restaurés.
Supprimer tout fichier présent dans pg_wal/
;
ils proviennent de la sauvegarde et sont du coup probablement obsolètes.
Si pg_wal/
n'a pas été archivé, il suffit de
recréer ce répertoire en faisant attention à le créer en tant que
lien symbolique, si c'était le cas auparavant.
Si des fichiers de segment WAL non archivés ont été sauvegardés dans
l'étape 2, les copier dans pg_wal/
. Il
est préférable de les copier plutôt que de les déplacer afin qu'une
version non modifiée de ces fichiers soit toujours disponible si un
problème survient et qu'il faille recommencer.
Créer un fichier de commandes de récupération
recovery.conf
dans le répertoire des données du
cluster (voir Chapitre 27). Il peut, de
plus, être judicieux de modifier temporairement le fichier
pg_hba.conf
pour empêcher les utilisateurs
ordinaires de se connecter tant qu'il n'est pas certain que la
récupération a réussi.
Démarrer le serveur. Le serveur se trouve alors en mode récupération et
commence la lecture des fichiers WAL archivés dont il a besoin. Si la
récupération se termine sur une erreur externe, le serveur peut tout
simplement être relancé. Il continue alors la récupération. À la
fin du processus de récupération, le serveur renomme
recovery.conf
en recovery.done
(pour éviter de retourner accidentellement en mode de récupération), puis passe en mode de
fonctionnement normal.
Inspecter le contenu de la base de données pour s'assurer que la
récupération a bien fonctionné. Dans le cas contraire, retourner
à l'étape 1. Si tout va bien, le fichier pg_hba.conf
peut-être restauré pour autoriser les utilisateurs à se reconnecter.
Le point clé de tout ceci est l'écriture d'un fichier de configuration de
récupération qui décrit comment et jusqu'où récupérer. Le fichier
recovery.conf.sample
(normalement présent dans le
répertoire d'installation share/
) peut être utilisé
comme prototype. La seule chose qu'il faut absolument préciser dans
recovery.conf
, c'est restore_command
qui indique à PostgreSQL comment récupérer les
fichiers de segment WAL archivés. À l'instar
d'archive_command
, c'est une chaîne de commande
shell. Elle peut contenir %f
, qui est
remplacé par le nom du journal souhaité, et %p
, qui est
remplacé par le chemin du répertoire où copier le journal.
(Le nom du chemin est relatif au répertoire de travail du serveur,
c'est-à-dire le répertoire des données du cluster.) Pour écrire le
caractère %
dans la commande, on utilise
%%
. La commande la plus simple ressemble à :
restore_command = 'cp /mnt/serveur/répertoire_archive/%f %p'
qui copie les segments WAL précédemment archivés à partir du répertoire
/mnt/serveur/répertoire_archive
. Il est toujours
possible d'utiliser une commande plus compliquée, voire même un script shell
qui demande à l'utilisateur de monter la cassette appropriée.
Il est important que la commande retourne un code de sortie différent de zéro en cas d'échec. Des fichiers absents de l'archive seront demandés à la commande ; elle doit renvoyer autre chose que zéro dans ce cas. Ce n'est pas une condition d'erreur. Une exception est possible si la commande a été terminée par un signa (autre que SIGTERM, qui est utilisé pour l'arrêt du serveur) ou si une erreur shell (comme une commande introuvable). Dans ces cas, la restauration va s'arrêter et le serveur ne démarrera plus.
Tous les fichiers demandés ne seront pas des segments WAL ; vous
pouvez aussi vous attendre à des demandes de fichiers suffixés par
.history
. Il faut également garder à l'esprit que le
nom de base du chemin %p
diffère de
%f
; ils ne sont pas interchangeables.
Les segments WAL qui ne se trouvent pas dans l'archive sont
recherchés dans pg_wal/
; cela autorise l'utilisation
de segments récents non archivés. Néanmoins, les segments disponibles
dans l'archive sont utilisés de préférence aux fichiers contenus dans
pg_wal/
.
Normalement, la récupération traite tous les segments WAL disponibles,
restaurant du coup la base de données à l'instant présent (ou aussi proche
que possible, en fonction des segments WAL disponibles). Une
récupération normale se finit avec un message « fichier non
trouvé », le texte exact du message d'erreur dépendant du
choix de restore_command
. Un message d'erreur au
début de la récupération peut également apparaître concernant un fichier nommé
dont le nom ressemble à 00000001.history
. Ceci est aussi normal et
n'indique pas un problème dans les situations de récupération habituelles. Voir
Section 25.3.5 pour plus d'informations.
Pour récupérer à un moment précis (avant que le DBA junior n'ait supprimé
la table principale), il suffit d'indiquer le point d'arrêt requis dans
recovery.conf
. Le point d'arrêt, aussi nommé
« recovery target » (cible de récupération), peut être précisé
par une combinaison date/heure, un point de récupération nommé ou par le
dernier identifiant de transaction. Actuellement, seules les options
date/heure et point de récupération nommé sont vraiment utilisables car il
n'existe pas d'outils permettant d'identifier avec précision l'identifiant
de transaction à utiliser.
Le point d'arrêt doit être postérieur à la fin de la sauvegarde
de la base (le moment où pg_stop_backup
se
termine). Une sauvegarde ne peut pas être utilisée pour repartir d'un
instant où elle était encore en cours (pour ce faire,
il faut récupérer la sauvegarde précédente et rejouer à partir de là).
Si la récupération fait face à une corruption des données WAL,
elle se termine à ce point et le serveur ne démarre pas. Dans un tel cas,
le processus de récupération peut alors être ré-exécuté à partir du début
en précisant une « cible de récupération » antérieure au point de
récupération pour permettre à cette dernière de se terminer correctement.
Si la récupération échoue pour une raison externe (arrêt brutal du système
ou archive WAL devenue inaccessible), la récupération peut être
simplement relancée. Elle redémarre alors quasiment là où elle a échoué.
Le redémarrage de la restauration fonctionne comme les points de
contrôle du déroulement normal : le serveur force une écriture
régulière de son état sur les disques et actualise alors le fichier
pg_control
pour indiquer que les données WAL déjà
traitées n'ont plus à être parcourues.
La possibilité de restaurer la base de données à partir d'un instantané crée une complexité digne des histoires de science-fiction traitant du voyage dans le temps et des univers parallèles.
Par exemple, dans l'historique original de la base de données, supposez qu'une table critique ait été supprimée à 17h15 mardi soir, mais personne n'a réalisé cette erreur avant mercredi midi. Sans stress, la sauvegarde est récupérée et restaurée dans l'état où elle se trouvait à 17h14 mardi soir. La base est fonctionnelle. Dans cette histoire de l'univers de la base de données, la table n'a jamais été supprimée. Or, l'utilisateur réalise peu après que ce n'était pas une si grande idée et veut revenir à un quelconque moment du mercredi matin. Cela n'est pas possible, si, alors que la base de données est de nouveau fonctionnelle, elle réutilise certaines séquences de fichiers WAL qui permettent de retourner à ce point. Il est donc nécessaire de pouvoir distinguer les séries d'enregistrements WAL engendrées après la récupération de l'instantané de celles issues de l'historique originel de la base.
Pour gérer ces difficultés, PostgreSQL inclut la notion de lignes temporelles (ou timelines). Quand une récupération d'archive est terminée, une nouvelle ligne temporelle est créée pour identifier la série d'enregistrements WAL produits après cette restauration. Le numéro d'identifiant de la timeline est inclus dans le nom des fichiers de segment WAL. De ce fait, une nouvelle timeline ne réécrit pas sur les données engendrées par des timelines précédentes. En fait, il est possible d'archiver plusieurs timelines différentes. Bien que cela semble être une fonctionnalité inutile, cela peut parfois sauver des vies. Dans une situation où l'instantané à récupérer n'est pas connu avec certitude, il va falloir tester les récupérations de différents instantanés jusqu'à trouver le meilleur. Sans les timelines, ce processus engendre vite un bazar ingérable. Avec les timelines, il est possible de récupérer n'importe quel état précédent, même les états de branches temporelles abandonnées.
Chaque fois qu'une nouvelle timeline est créée, PostgreSQL crée un fichier d'« historique des timelines » qui indique à quelle timeline il est attaché, et depuis quand. Ces fichiers d'historique sont nécessaires pour permettre au système de choisir les bons fichiers de segment WAL lors de la récupération à partir d'une archive qui contient plusieurs timelines. Ils sont donc archivés comme tout fichier de segment WAL. Puisque ce sont de simples fichiers texte, il est peu coûteux et même judicieux de les conserver indéfiniment (contrairement aux fichiers de segment, volumineux). Il est possible d'ajouter des commentaires au fichier d'historique expliquant comment et pourquoi cette timeline a été créée. De tels commentaires s'avèrent précieux lorsque l'expérimentation conduit à de nombreuses timelines.
Par défaut, la récupération s'effectue sur la timeline en vigueur au
cours de la sauvegarde. Si l'on souhaite effectuer la récupération
dans une timeline fille (c'est-à-dire retourner à un état enregistré
après une tentative de récupération), il faut préciser l'identifiant de la timeline
dans recovery.conf
. Il n'est pas possible de
récupérer dans des timelines antérieures à la sauvegarde.
Quelques conseils de configuration de l'archivage continue sont donnés ici.
Il est possible d'utiliser les capacités de sauvegarde de PostgreSQL pour produire des sauvegardes autonomes à chaud. Ce sont des sauvegardes qui ne peuvent pas être utilisées pour la récupération à un instant donné, mais ce sont des sauvegardes qui sont typiquement plus rapide à obtenir et à restaurer que ceux issus de pg_dump. (Elles sont aussi bien plus volumineuses qu'un export pg_dump, il se peut donc que l'avantage de rapidité soit négatif.)
Comme pour les sauvegarde de base, la manière la plus simple de
créer une sauvegarde à chaud autonome est d'utiliser l'outil
pg_basebackup. Si vous ajoutez le
paramètre -X
au lancement de la sauvegarde,
tout l'historique de transaction ("transaction log") nécessaire
sera inclus automatiquement dans la sauvegarde et vous n'aurez pas
d'action supplémentaire à effectuer pour restaurer votre sauvegarde.
Si vous avez besoin de plus de flexibilité pour copier les
fichiers de sauvegarde, un processus bas niveau peut être utilisé
pour les sauvegardes à chaud autonomes.
En vue d'effectuer des sauvegardes à chaud autonomes, on positionne
wal_level
à
replica
ou supérieur,
archive_mode
à on
, et on configure
archive_command
de telle sorte que l'archivage ne soit
réalisé que lorsqu'un fichier de bascule existe. Par
exemple :
archive_command = 'test ! -f /var/lib/pgsql/backup_in_progress || (test ! -f /var/lib/pgsql/archive/%f && cp %p /var/lib/pgsql/archive/%f)'
Cette commande réalise l'archivage dès lors que
/var/lib/pgsql/backup_in_progress
existe. Dans le
cas contraire, elle
renvoie silencieusement le code de statut zéro (permettant à
PostgreSQL de recycler le journal de
transactions non désiré).
Avec cette préparation, une sauvegarde peut être prise en utilisant un script comme celui-ci :
touch /var/lib/pgsql/backup_in_progress psql -c "select pg_start_backup('hot_backup');" tar -cf /var/lib/pgsql/backup.tar /var/lib/pgsql/data/ psql -c "select pg_stop_backup();" rm /var/lib/pgsql/backup_in_progress tar -rf /var/lib/pgsql/backup.tar /var/lib/pgsql/archive/
Le fichier de bascule,
/var/lib/pgsql/backup_in_progress
, est créé en
premier, activant l'archivage des journaux de transactions pleins.
Après la sauvegarde, le fichier de bascule est supprimé. Les journaux
de transaction archivés sont ensuite ajoutés à la sauvegarde pour que
la sauvegarde de base et les journaux requis fassent partie du même
fichier tar.
Rappelez vous d'ajouter de la gestion d'erreur à vos scripts.
Si la taille du stockage des archives est un problème, vous pouvez utiliser gzip pour compresser les fichiers archives :
archive_command = 'gzip < %p > /var/lib/pgsql/archive/%f'
Vous aurez alors besoin d'utiliser gunzip pendant la récupération :
restore_command = 'gunzip < /mnt/server/archivedir/%f > %p'
archive_command
Nombreux sont ceux qui choisissent d'utiliser
des scripts pour définir leur archive_command
, de
sorte que leur postgresql.conf
semble très simple :
archive_command = 'local_backup_script.sh "%p" "%f"'
Utiliser un script séparé est conseillé à chaque fois qu'il est envisagé d'utiliser plusieurs commandes pour le processus d'archivage. Ainsi toute la complexité est gérée dans le script qui peut être écrit dans un langage de scripts populaires comme bash ou perl.
Quelques exemples de besoins résolus dans un script :
copier des données vers un stockage distant ;
copier les journaux de transaction en groupe pour qu'ils soient transférés toutes les trois heures plutôt qu'un à la fois ;
s'interfacer avec d'autres outils de sauvegarde et de récupération ;
s'interfacer avec un outil de surveillance pour y renvoyer les erreurs.
Lors de l'utilisation d'un script archive_command
,
il est préférable d'activer logging_collector.
Tout message écrit sur stderr à partir du script
apparaîtra ensuite dans les traces du serveur, permettant un diagnostic
facilité de configurations complexes en cas de problème.
Au moment où ces lignes sont écrites, plusieurs limitations de la technique d'archivage continu sont connues. Elles seront probablement corrigées dans une prochaine version :
Si une commande
CREATE DATABASE
est exécutée alors qu'une sauvegarde est en cours, et que la base de données
modèle utilisée par l'instruction CREATE DATABASE
est à son tour modifiée pendant la sauvegarde, il est
possible que la récupération propage ces modifications
dans la base de données créée. Pour éviter ce risque, il est préférable de
ne pas modifier les bases de données modèle lors d'une sauvegarde de base.
Les commandes CREATE TABLESPACE sont tracées dans les WAL avec le chemin absolu et sont donc rejouées en tant que créations de tablespace suivant le même chemin absolu. Cela n'est pas forcément souhaitable si le journal est rejoué sur une autre machine. De plus, cela peut s'avérer dangereux même lorsque le journal est rejoué sur la même machine, mais dans un répertoire différent : la ré-exécution surcharge toujours le contenu du tablespace original. Pour éviter de tels problèmes, la meilleure solution consiste à effectuer une nouvelle sauvegarde de la base après la création ou la suppression de tablespace.
Il faut de plus garder à l'esprit que le format actuel des
WAL est extrêmement volumineux car il inclut
de nombreuses images des pages disques. Ces images de page sont conçues
pour supporter la récupération après un arrêt brutal, puisqu'il peut
être nécessaire de corriger des pages disque partiellement écrites.
En fonction du matériel et des logiciels composant le système,
le risque d'écriture partielle peut être
suffisamment faible pour être ignoré, auquel cas le volume total des
traces archivées peut être considérablement réduit par la désactivation
des images de page à l'aide du paramètre full_page_writes
(lire les notes et avertissements dans Chapitre 30 avant
de le faire). Désactiver les images de page n'empêche pas l'utilisation des
traces pour les opérations PITR. Un piste éventuelle de développement
futur consiste à compresser les données des WAL archivés en supprimant les copies
inutiles de pages même si full_page_writes
est actif. Entre
temps, les administrateurs peuvent souhaiter réduire le nombre
d'images de pages inclus dans WAL en augmentant autant que possible les
paramètres d'intervalle entre les points de vérification.