IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

24.3. Archivage continu et récupération d'un instantané (PITR)

PostgreSQL™ maintient en permanence des journaux WAL (write ahead log) dans le sous-répertoire pg_xlog/ 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.

[Note]

Note

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.

24.3.1. Configurer l'archivage 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 gravage 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 à archive (ou à hot_standby), 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_xlog/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_xlog/ continue à se remplir de fichiers de segment WAL jusqu'à la résolution de la situation. (Si le système de fichiers contenant pg_xlog/ 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_xlog/ 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 18.2, « Emplacement des fichiers » 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_xlog. 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.56, « Fonctions de contrôle de la sauvegarde ».

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, « Désactiver l'archivage des journaux de transactions et la réplication en flux ». 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_xlog/ jusqu'au rétablissement d'un paramètre archive_command fonctionnel.

24.3.2. Réaliser une sauvegarde de base

La procédure pour réaliser une sauvegarde de base est relativement simple :

  1. S'assurer que l'archivage WAL est activé et fonctionnel.

  2. Se connecter à la base de données en tant que superutilisateur et lancer la commande :

    SELECT pg_start_backup('label');
    

    label est une chaîne utilisée pour identifier de façon unique l'opération de sauvegarde (une bonne pratique est d'utiliser le chemin complet du fichier 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 base de données de connexion utilisée pour lancer cette commande n'a aucune importance. Le résultat de la fonction peut être ignoré, mais il faut gérer l'erreur éventuelle avant de continuer.

    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.

  3. 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.

  4. Se connecter à nouveau à la base de données en tant que superutilisateur et lancer la commande :

    SELECT pg_stop_backup();
    

    Cela 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.

  5. 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.

Vous pouvez aussi utiliser l'outil pg_basebackup(1) pour faire la sauvegarde, à la place d'une copie manuelle des fichiers. Cet outil fera l'équivalent des étapes pg_start_backup(), copie et pg_stop_backup() automatiquement, et transfert la sauvegarde via une connexion standard PostgreSQL™ en utilisant le protocole de réplication, au lieu d'avoir besoin d'un accès au niveau du système de fichiers. pg_basebackup n'interfère pas avec les sauvegardes de niveau système de fichiers prises à l'aide de pg_start_backup()/pg_stop_backup().

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.

Il n'est pas utile d'accorder de l'importance au temps passé entre pg_start_backup et le début réel de la sauvegarde, pas plus qu'entre la fin de la sauvegarde et pg_stop_backup ; un délai de quelques minutes ne pose pas de problème. (Néanmoins, si le serveur est normalement utilisé alors que full_page_writes est désactivé, une perte de performances entre pg_start_backup et pg_stop_backup peut être constatée car l'activation du paramètre full_page_writes est forcée lors du mode de sauvegarde.) Il convient toutefois de s'assurer que ces étapes sont effectuées séquentiellement, sans chevauchement. Dans le cas contraire, la sauvegarde est invalidée.

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_xlog/, contenu dans le répertoire du cluster, peuvent ê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_xlog/ 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.

La sauvegarde n'est utilisable que si les fichiers de segment WAL engendrés pendant ou après cette sauvegarde sont préservés. Pour faciliter cela, la fonction pg_stop_backup crée un fichier d'historique de la sauvegarde immédiatement stocké dans la zone d'archivage des WAL. Ce fichier est nommé d'après le nom du premier fichier segment WAL nécessaire à l'utilisation de la sauvegarde. Ainsi, si le fichier WAL de démarrage est 0000000100001234000055CD, le nom du fichier d'historique ressemble à 0000000100001234000055CD.007C9330.backup (le deuxième nombre dans le nom de ce fichier contient la position exacte à l'intérieur du fichier WAL et peut en général être ignoré). Une fois que la sauvegarde du système de fichiers et des segments WAL utilisés pendant celle-ci (comme précisé dans le fichier d'historique des sauvegardes) est archivée de façon sûre, tous les segments WAL archivés de noms numériquement plus petits ne sont plus nécessaires à la récupération de la sauvegarde du système de fichiers et peuvent être supprimés. Toutefois, il est préférable de conserver plusieurs jeux de sauvegarde pour être absolument certain de pouvoir récupérer les données.

Le fichier d'historique de la sauvegarde est un simple fichier texte. Il contient le label passé à pg_start_backup, l'heure et les segments WAL de début et de fin de la sauvegarde. Si le label est utilisé pour identifier l'endroit où le fichier de sauvegarde associé est conservé, alors le fichier d'historique archivé est suffisant pour savoir quel fichier de sauvegarde restaurer, en cas de besoin.

Puisqu'il faut conserver tous les fichiers WAL archivés depuis la dernière sauvegarde de base, l'intervalle entre les sauvegardes de base est habituellement choisi en fonction de l'espace de stockage qu'on accepte de consommer en fichiers d'archives WAL. Il faut également considérer le temps à dépenser pour la récupération, si celle-ci s'avère nécessaire -- le système doit rejouer tous les segments WAL et ceci peut prendre beaucoup de temps si la dernière sauvegarde de base est ancienne.

La fonction pg_start_backup crée un fichier nommé backup_label dans le répertoire du cluster de bases de données. Ce fichier est ensuite supprimé par pg_stop_backup. Ce fichier est archivé dans le fichier de sauvegarde. 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.

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és. 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.

24.3.3. Récupération à partir d'un archivage continu

Le pire est arrivé et il faut maintenant repartir d'une sauvegarde. Voici la procédure :

  1. Arrêter le serveur s'il est en cours d'exécution.

  2. 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_xlog 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.

  3. 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.

  4. 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.

  5. Supprimer tout fichier présent dans pg_xlog/ ; ils proviennent de la sauvegarde et sont du coup probablement obsolètes. Si pg_xlog/ 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.

  6. Si des fichiers de segment WAL non archivés ont été sauvegardés dans l'étape 2, les copier dans pg_xlog/. 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.

  7. Créer un fichier de commandes de récupération recovery.conf dans le répertoire des données du cluster (voir Chapitre 26, Configuration de la récupération). 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.

  8. 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.

  9. 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. Tous les fichiers demandés ne seront pas des segmets WAL; vous pouvez aussi vous attendre à des demandes de fichiers suffixés par .backup or .history. Il faut également garder à l'esprit que le nom de base du chemin %p diffère de %f ; il ne sont pas interchangeables.

Les segments WAL qui ne se trouvent pas dans l'archive sont recherchés dans pg_xlog/ ; 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_xlog/. Le système ne surcharge pas le contenu de pg_xlog/ lors de la récupération des fichiers archivés.

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 par un problème dans les situations de récupération habituelles. Voir Section 24.3.4, « Lignes temporelles (Timelines) » 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.

[Note]

Note

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.

24.3.4. Lignes temporelles (Timelines)

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 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.

24.3.5. Conseils et exemples

Quelques conseils de configuration de l'archivage continue sont donnés ici.

24.3.5.1. Configuration de la récupération

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.)

En vue d'effectuer des sauvegardes à chaud autonomes, on positionne wal_level à archive (ou hot_standby), 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.

24.3.5.2. Compression des journaux archivés

Si la taille du stockage des archives est un problème, utilisez pg_compresslog, http://pglesslog.projects.postgresql.org, afin d'enlever les inutiles full_page_writes et les espaces de fin des journaux de transactions. Vous pouvez utiliser gzip pour compresser encore davantage le résultat de pg_compresslog :

          archive_command = 'pg_compresslog %p - | gzip > /var/lib/pgsql/archive/%f'

Vous aurez alors besoin d'utiliser gunzip et pg_decompresslog pendant la récupération :

          restore_command = 'gunzip < /mnt/server/archivedir/%f | pg_decompresslog - %p'

24.3.5.3. Scripts 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.

[Astuce]

Astuce

Lors de l'utilisation du script archive_command, il est préférable d'activer logging_collector. Tout message envoyé dans stderr à partir du script apparaîtra dans les traces du serveur, permettant un diagnostic plus aisé de configurations complexes en cas de problème.

24.3.6. Restrictions

Au moment où ces lignes sont écrites, plusieurs limitations de la technique d'achivage continu sont connues. Elles seront probablement corrigées dans une prochaine version :

  • Les opérations sur les index de hachage ne sont pas tracées dans les journaux de transactions. Ces index ne sont donc pas actualisés lorsque la sauvegarde est rejouée. Cela signifie que toute nouvelle insertion sera ignorée par l'index, que les lignes mises à jour sembleront disparaître et que les lignes supprimées auront toujours leur pointeurs. En d'autres termes, si vous modifier une table disposant d'un index hash, alors vous obtiendrez des résultats erronés sur un serveur en attente. Lorsque la restauration se termine, il est recommandé de lancer manuellement la commande REINDEX(7) sur chacun des index à la fin de la récupération.

  • Si une commande CREATE DATABASE(7) 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(7) 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ée 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 29, Fiabilité et journaux de transaction 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.