PostgreSQL maintient en permanence des journaux
de transactions(Write Ahead Log ou
WAL) dans le sous-répertoire
pg_wal/
du répertoire de données de l'instance. 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 checkpoint. 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 journaux de transactions. Si la
restauration est nécessaire, la sauvegarde des fichiers est restaurée,
puis les journaux de transactions 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 importants :
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'un rejeu 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 journaux de transactions peut être assemblée pour être rejoués, une sauvegarde continue est obtenue en continuant simplement à archiver les journaux de transactions. 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 des journaux de transactions 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 restauration 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 journaux de transactions 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 contient 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'une instance 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 de journaux de transactions à 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 restauration fructueuse à partir de l'archivage continu (aussi appelé « sauvegarde à chaud » par certains vendeurs de SGBD) nécessite une séquence ininterrompue de journaux de transactions 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 de transactions 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 journaux de transactions.
Au sens abstrait, un système PostgreSQL fonctionnel produit une séquence infinie d'enregistrements de journaux de transactions. 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 l'exécution d'initdb). Les fichiers segment reçoivent des noms numériques pour refléter leur position dans la séquence abstraite des journaux de transactions. Lorsque le système n'utilise pas l'archivage des journaux de transactions, il ne crée que quelques fichiers segments, qu'il « recycle » en renommant les fichiers devenus inutiles. Un fichier segment dont le contenu précède le dernier checkpoint est supposé inutile et peut être recyclé.
Lors de l'archivage des journaux de transactions, 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 de l'instance.)
%%
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 journaux de transactions 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 de l'archiver jusqu'à la réussite de l'opération.
Quand la commande d'archivage est arrêtée par un signal (autre que SIGTERM qui est utilisé lors d'un arrêt du serveur) ou une erreur du shell avec un code d'erreur supérieur à 125 (par exemple pour un programme introuvable), le processus d'archivage quitte et est relancé par postmaster. Dans de tels cas, l'échec n'est pas indiqué par pg_stat_archiver.
En général, la commande d'archivage doit être conçue pour refuser d'écraser tout fichier archive déjà existant. 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 renvoie 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 journaux de transactions 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 remplir 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 des journaux de transactions 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 20.2 pour savoir comment modifier
l'emplacement des fichiers de configuration.
La commande d'archivage n'est appelée que sur les fichiers segments WAL
complets. Du coup, si le serveur engendre peu de trafic dans les journaux
de transactions (ou qu'il y a des périodes de calme où le trafic est
léger), il peut y avoir un long délai entre la fin d'une transaction et
son enregistrement garanti dans le stockage d'archive. Pour placer une
limite sur l'ancienneté des données archivées, il faut configurer archive_timeout, ce qui permet de forcer 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 journaux de
transactions sont disponibles dans Tableau 9.87.
Quand wal_level
est configuré à la valeur
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 sont
activés lors de l'exécution d'une de ces instructions, les journaux de
transaction ne contiennent pas suffisamment d'informations pour une
restauration via les archives. (La restauration 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 (''
) dans
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 revient à utiliser l'outil pg_basebackup. Il peut créer une sauvegarde de base sous la forme soit de fichiers standards, soit d'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 26.3.3).
La durée d'une sauvegarde de base n'est pas toujours un critère
déterminant. Toutefois, si vous exploitez votre serveur 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 fichiers
segments WAL générés pendant et après la sauvegarde des fichiers. Pour
vous aider dans cette tâche, le processus de sauvegarde crée un
fichier historique de sauvegarde qui est
immédiatement enregistré dans la zone d'archivage des journaux de
transactions. Le nom de ce fichier reprend le nom du premier fichier
segment WAL que vous devez conserver. Par exemple, si le premier fichier
segment 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 segment WAL. Cette information peut être ignorée.)
Une fois que vous avez archivé avec précaution la sauvegarde de base et
les fichiers segments WAL générés pendant la sauvegarde (tel qu'indiqué
par le fichier historique de sauvegarde), tous les fichiers segments 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 fichiers 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 segments 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 segments WAL. Vous devez également prendre en compte le temps de restauration (le système devra rejouer tous les fichiers 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 soient 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 prochainement 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 des journaux de transactions est activé et fonctionnel.
Se connecter au serveur (peu importe la base) en tant qu'utilisateur
ayant les droits d'exécuter la fonction
pg_start_backup
(donc soit un super-utilisateur,
soit un utilisateur ayant gagné le droit EXECUTE
sur cette 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. Dans le cas contraire, 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 checkpoint, et que les entrées/sorties pour
l'établissement de ce checkpoint seront réparties sur une grande
durée, par défaut la moitié de l'intervalle entre deux checkpoints
automatiques (voir le paramètre de configuration checkpoint_completion_target). Habituellement, ce
comportement est appréciable, car il minimise l'impact sur le
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
, il 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 26.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, 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 devra être écrit dans un
fichier nommé backup_label
dans le répertoire
racine de la sauvegarde. Le troisième champ devra ê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 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 serveur secondaire, le paramètre
archive_mode
doit valoir always
pour que la fonction pg_stop_backup
soit en
attente. 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 segments 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 journal de
transaction en cours. Par défaut, pg_stop_backup
attendra jusqu'à ce que tous les journaux de transactions aient été
archivés, ce qui peut prendre un certain temps. Cette option doit
être utilisée avec précaution : si l'archivage des journaux de
transactions n'est pas supervisé correctement, alors la sauvegarde
pourrait ne pas inclure tous les fichiers segments WAL, et serait
donc incomplète et impossible à restaurer.
La méthode de sauvegarde exclusive est obsolète et devrait être évitée. Avant PostgreSQL 9.6, il s'agissait de la seule méthode bas-niveau disponible, mais il est désormais recommandé que tous les utilisateurs mettent à jour leurs scripts pour utiliser la sauvegarde non-exclusive.
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. De plus, le fichier
backup_label
créé sur un serveur primaire peut
empêcher le redémarrage de celui-ci en cas de crash. D'un autre côté, la
suppression à tord de ce fichier d'une sauvegarde ou d'un serveur
secondaire est une erreur fréquente qui peut mener à de sérieuses
corruptions de données. S'il était nécessaire d'utiliser cette méthode,
les étapes suivantes doivent être respectées.
S'assurer que l'archivage des journaux de transactions est activé et fonctionnel.
Se connecter au serveur (peu importe la base) en tant qu'utilisateur
ayant les droits d'exécuter la fonction
pg_start_backup
(donc soit un super-utilisateur,
soit un utilisateur ayant gagné 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 de l'instance.
Ce fichier contient les informations de la sauvegarde, ceci incluant
le moment du démarrage de la sauvegarde et le label. La fonction crée
aussi un fichier de recensement des
tablespaces, 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 checkpoint, et que les entrées/sorties pour la réalisation de ce
checkpoint seront réparties sur une grande durée, par défaut la
moitié de l'intervalle entre deux checkpoints automatiques(voir le
paramètre de configuration checkpoint_completion_target). Habituellement, ce
comportement est intéressant 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 checkpoint 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 26.3.3.3 pour les considérations à prendre en compte durant cette sauvegarde.
Comme il est déjà indiqué ci-dessus, 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
.
Il est très important de ne jamais supprimer le fichier
backup_label
lors de la restauration d'une
sauvegarde afin d'éviter toute corruption. La confusion concernant
les cas d'usage où il est approprié de supprimer ce fichier est une
cause fréquente de corruption de données lors de l'utilisation de
cette méthode de sauvegarde ; il faut s'assurer de ne supprimer
ce fichier que sur un serveur primaire fonctionnel et jamais lors de
la construction d'un serveur secondaire ou lors de la restauration
d'une sauvegarde, même lors de la construction d'un serveur
secondaire qui sera par la suite promu comme nouveau serveur
primaire.
Se connecter à nouveau à la base de données en tant qu'utilisateur
ayant le droit d'exécuter la fonction
pg_stop_backup
(donc soit un super-utilisateur,
ou soit un utilisateur ayant gagné 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 fichier segment WAL. Cette bascule est nécessaire pour permettre au dernier fichier segment WAL écrit pendant la sauvegarde d'être immédiatement archivable.
Une fois que les fichiers 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 sauvegarde. 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 la sauvegarde soit complète.
Lors de l'utilisation de la méthode de sauvegarde exclusive, il est
absolument impératif de s'assurer que
pg_stop_backup
se termine correctement à la fin
de la sauvegarde. Même si la sauvegarde elle-même échoue, par exemple
à cause d'un manque d'espace disque, ne pas exécuter
pg_stop_backup
laisse le serveur en mode
sauvegarde indéfiniment, empêchant la réalisation des futures
sauvegardes et augmentant le risque que le serveur ne puisse pas
redémarrer lorsque le fichier backup_label
existe.
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 dde l'instance
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 de l'instance, 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 de
l'instance, ce qui est une configuration courante pour des raisons de
performance. Il peut être aussi 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 primaire ne deviennent
pas partie intégrante de la sauvegarde. Dans le cas contraire,
l'utilisation de la sauvegarde pour créer un secondaire pourrait
résulter en une rétention infinie des journaux de transactions sur le
secondaire et aussi de la fragmentation sur le primaire si les messages
de retour d'un secondaire 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 primaire et non pas sur le
secondaire. Même si la sauvegarde a pour but d'être utilisée pour la
création d'un nouveau primaire, 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
primaire 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)
peut être exclu de la sauvegarde puisqu'il sera réinitialisé au
démarrage de postmaster. Si stats_temp_directory
est positionné et qu'il pointe sur 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és au démarrage de postmaster et les répertoires
seront recréés si nécessaire.
Les fichiers pg_internal.init
peuvent être omis de
la sauvegarde quand un fichier de ce nom est trouvé. Ces fichiers
contiennent les données du cache des relations qui est toujours
reconstruit lors de la restauration.
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ée et le nom du fichier
segment WAL initial. En cas de confusion, il est ainsi possible de
regarder dans ce fichier de label et de déterminer avec précision de
quelle session de sauvegarde il provient. 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, les fonctions 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 segments
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 de l'instance 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 de l'instance 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 de l'instance 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 segments 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.
Configurer les commandes de restauration dans
postgresql.conf
(voir Section 20.5.4) et créer un fichier
recovery.signal
dans le répertoire des données de
l'instance. De plus, il peut ê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 restauration a réussi.
Démarrer le serveur. Le serveur se trouve alors en mode restauration et
commence la lecture des fichiers segments WAL archivés dont il a
besoin. Si la restauration se termine sur une erreur externe, le
serveur peut tout simplement être relancé. Il continue alors la
restauration. À la fin du processus de restauration, le serveur
supprime le fichier recovery.signal
(pour éviter
de retourner accidentellement en mode de restauration), puis passe en
mode de fonctionnement normal.
Inspecter le contenu de la base de données pour s'assurer que la
restauration 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 la configuration de la restauration qui
décrit comment et jusqu'où restaurer. La seule chose qu'il faut
absolument préciser dans postgresql.conf
, c'est la
valeur du paramètre restore_command
qui indique à
PostgreSQL comment récupérer les fichiers
segments 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 fichiers 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 renvoie 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 signal (autre que SIGTERM, qui est utilisé pour l'arrêt du serveur) ou par 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 fichiers 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 fichiers 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
restauration 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 restauration
standards. Voir Section 26.3.5 pour plus
d'informations.
Pour restaurer jusqu'à un moment précis (avant que le DBA junior n'ait supprimé la table principale par exemple), il suffit d'indiquer le point d'arrêt requis. Le point d'arrêt, aussi nommé « cible de récupération » (« recovery target » dans la version originale) , peut être précisé par une combinaison de date et d'heure, par un point de restauration nommé ou par un identifiant de transaction. Actuellement, seules les options date/heure et point de restauration 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 restauration fait face à une corruption des données des journaux de
transactions, le rejeu s'interrompt juste avant la corruption détectée et
le serveur ne démarre pas. Dans un tel cas, le processus de restauration
peut alors être ré-exécuté à partir du début en précisant une
« cible de restauration » antérieure au point de corruption
pour permettre à cette dernière de se terminer correctement. Si la
restauration échoue pour une raison externe (arrêt brutal du système ou
archive devenue inaccessible), la restauration peut être simplement
relancée. Elle redémarre alors quasiment là où elle a échoué. Le
redémarrage de la restauration fonctionne comme les checkpoints 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 déjà
traitées des journaux de transactions 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 que personne n'ait 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 segments WAL qui permettent de retourner à ce point. Il est donc nécessaire de pouvoir distinguer les séries d'enregistrements des journaux de transactions engendrées après la restauration 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 de journaux de transactions produits après cette restauration. Le numéro d'identifiant de la timeline est inclus dans le nom des fichiers segments 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é à restaurer n'est pas connu avec certitude, il va falloir tester les restaurations 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 restaurer 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 segments WAL lors de la restauration à partir d'une archive qui contient plusieurs timelines. Ils sont donc archivés comme tout fichier 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 segments, bien plus 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 restauration s'effectue jusqu'à la dernière timeline
trouvée dans l'archive. Si vous souhaitez effectuer la restauration
uniquement pour la timeline de la sauvegarde ou jusqu'à une timeline
précise (c'est-à-dire retourner à un état enregistré après une tentative
de restauration), il faut préciser current
ou
l'identifiant de la timeline cible dans recovery_target_timeline. Il n'est pas possible de
restaurer dans des timelines antérieures à la sauvegarde.
Quelques conseils de configuration de l'archivage continu 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 restauration à un instant donné, mais ce sont des sauvegardes qui sont typiquement plus rapides à obtenir et à restaurer que celles issues 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 sauvegardes 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
des transactions 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 vu 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 le fichier
/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 > /mnt/server/archivedir/%f'
Vous aurez alors besoin d'utiliser gunzip pendant la restauration :
restore_command = 'gunzip < /mnt/server/archivedir/%f.gz > %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 transactions 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 restauration ;
s'interfacer avec un outil de surveillance pour y renvoyer les erreurs.
Lors de l'utilisation d'un script pour le paramètre
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 en 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 journaux de
transactions 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.
De plus, il faut garder à l'esprit que le format actuel des journaux de
transactions est extrêmement volumineux car il inclut de nombreuses
images complètes des blocs disques. Ces images de bloc sont conçues pour
supporter la restauration après un arrêt brutal, puisqu'il peut être
nécessaire de corriger des blocs disque partiellement écrits. 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 bloc à 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 bloc
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
journaux de transactions archivés en supprimant les copies inutiles de
blocs même si full_page_writes
est actif. Entre temps,
les administrateurs peuvent souhaiter réduire le nombre d'images de blocs
inclus dans les journaux de transactions en augmentant autant que
possible les paramètres d'intervalle entre les checkpoints.