8 Les outils de réplication physique
Les outils de réplication physique
Le contenu comprend pg_rewind, pgBackRest, Barman, Patroni, repmgr, PAF et le TP avec solution. Pour le socle de réplication, voir les fondamentaux.

8/ Les outils de réplication physique
8.1 Introduction
- Les outils à la rescousse!
- (Re)construction d’un secondaire
- Log shipping & PITR
- Promotion automatique
Nous aborderons dans ce module différents outils externes qui peuvent nous aider à administrer notre cluster de réplication. (À noter : tout ce qui suit ne concerne que la réplication physique, à base de copie des fichiers de données, et non la réplication logique, qui fonctionne très différemment.)
8.1.1 Au menu
- (Re)construction d’un secondaire
- outils de copie
- pg_rewind
- Log shipping & PITR
- pgBackRest
- Barman
- Promotion automatique
- Patroni
- repmgr
- PAF
8.2 (re)construire un secondaire
Outils :
- pg_basebackup
- rsync
- outils PITR
- pg_rewind
8.2.1 (Re)construction d’un secondaire : pg_basebackup
- Simple et pratique
- …mais recopie tout!
est un outil éprouvé pour créer une sauvegarde physique, mais aussi un serveur
standby. Il est basé sur une réplication par streaming. Rappelons ses qualités et défauts dans le cadre de la réplication :
- il sait générer le postgresql.auto.conf et le standby.signal pour créer un secondaire en streaming (option –write-recovery-conf ) ;
- l’impact sur le réseau peut être limité grâce à l’option -r ( –max-rate );
- il peut poser ou utiliser un slot de réplication permanent pour éviter un décrochage dès le démarrage;
- il peut déplacer des tablespaces à un autre endroit (mapping);
- les journaux nécessaires peuvent être inclus et leur récupération sécurisée par un slot de réplication temporaire (c’est en général inutile pour (re)construire un secondaire). Par contre :
- pg_basebackup s’attend à créer un standby de zéro : le répertoire de données de destination doit être vide, répertoires des tablespaces compris : un ancien secondaire doit donc être détruit (penser à sauver la configuration!);
- il copiera à nouveau toutes les données, même si un ancien secondaire ou un ancien primaire presque identique existe;
- si la connexion est peu stable, le transfert échouera et sera à reprendre de zéro;
- les données transférées ne sont pas compressées avant la version 15 de PostgreSQL. (Re)construction : La sauvegarde générée, et si nécessaire décompressée, ne peut être utilisée directement pour créer une instance secondaire. Il faut :
- ajouter le fichier standby.signal dans le PGDATA;
- préciser comment récupérer les journaux ( restore_command ) ;
- et/ou paramétrer le streaming avec primary_conninfo , et éventuellement primary_slot_name .
Ces deux derniers points se paramètrent dans postgresql.conf ou postgresql.auto.conf .
Pour simplifier, pg_basebackup peut générer la configuration nécessaire dans le répertoire de la sauvegarde. Par exemple, il ajoutera ceci dans le postgresql.auto.conf :
Cette chaîne réutilise la chaîne fournie en appelant pg_basebackup , essaie de prévoir tous les types d’authentification, et positionne nombre de paramètres à leur valeur par défaut. Le plus souvent, utilisateur, port, hôte et passfile suffisent.
Si –slot=nom_du_slot a été précisé, apparaîtra aussi :
Le secondaire possède ainsi immédiatement toutes les informations pour se connecter au primaire. Il est tout de même conseillé de revérifier cette configuration et d’y ajouter la commande de récupération des archives si nécessaire.
8.2.2 (Re)construction d’un secondaire : script rsync
- Déconseillé si vous avez un autre outil
- Intérêts :
- reprendre des transferts interrompus
- compression
- Prévoir :
- pg_backup_start() / pg_backup_stop()
- rsync –whole-file
- les tablespaces
- ne pas tout copier!
- postgresql.conf
Selon les volumes de données mis en jeu, et encore plus avec une liaison instable, il est souvent plus intéressant d’utiliser rsync . En effet, rsync ne transfère que les fichiers ayant subi une modification. Le transfert sera beaucoup plus rapide s’il existe un secondaire, ou ancien primaire qui a « décroché ». Si le transfert a été coupé, rsync permet de le reprendre.
C’est évidemment plus fastidieux qu’un pg_basebackup direct, mais peut valoir le coup pour les grosses installations.
Voici un exemple d’utilisation :
Noter que l’on utilise –whole-file par précaution pour forcer le transfert entier d’un fichier de données en cas de détection d’une modification. C’est une précaution contre tout risque de corruption ( –inplace ne transférerait que les blocs modifiés). Les grosses tables sont fractionnées en fichiers de 1 Go, donc elles ne seront pas intégralement retransférées.
Lorsque la connexion utilisée est lente, il est courant de compresser les données pour le transfert (options -z / –compress et –compress-level , de 1 à 9), à ajuster en fonction du CPU disponible.
L’option –bwlimit limite au besoin le débit réseau.
Il faudra impérativement encadrer l’appel à rsync de pg_backup_start() et pg_backup_stop() , comme dans une sauvegarde PITR classique.
De nombreux fichiers ne doivent pas être copiés. La liste complète figure dans le module I2 - Point In Time Recovery 1 : https://dali.bo/i2_html ou la documentation officielle 2 . Les principaux sont postmaster.pid, et les sous-répertoires pg_wal, pg_replslot, pg_dynshmem, pg_notify, pg_serial, pg_snapshots, pg_stat_tmp et pg_subtrans, ainsi que pgsql_tmp*.
Pour créer le fichier postgresql.auto.conf , on peut prévoir un fichier modèle tout prêt, sous un autre nom, dans le répertoire PGDATA du serveur principal, qu’il suffira de renommer.
La liste des répertoires des tablespaces se trouve dans $PGDATA/pg_tblspc sous forme de liens symboliques pointant sur le répertoire du tablespace : on peut alors rendre le script générique pour la synchronisation des tablespaces.
Et il faudra bien tester!
Réinventer la roue avec ses propres scripts est rarement une bonne idée. Il est préférable d’utiliser des outils dédiés à la sauvegarde et la restauration qui se chargeront de tout ça.
- Source 1 : https://dali.bo/i2_html
- Source 2 : https://docs.postgresql.fr/current/continuous-archiving.html#BACKUP-LOWLEVEL-BASE-BACKUP
8.2.3 (Re)construction d’un secondaire : outil PITR
- Le plus confortable
- Ne charge pas le primaire
- Mode « delta »
Si l’on dispose d’un outil PITR, il permet souvent de créer un secondaire, et c’est généralement l’option la plus confortable.
L’exemple ci-dessus utilise pgBackRest pour créer un serveur secondaire dans le répertoire pointé. Les outils concurrents suivent le même principe.
Si le répertoire cible n’est pas vide (secondaire récemment décroché, ancien primaire, restauration échouée…), le paramètre –delta permet de ne copier que les différences entre la sauvegarde et le répertoire existant. Cela permet de gagner un temps précieux pour de grosses instances.
Pour simplifier, une bonne partie de ces options iront plutôt dans le fichier de configuration local
Les options de recovery demandées dans cet exemple apparaîtront dans le fichier postgresql.auto.conf , ainsi que la restore_command nécessaire pour récupérer les journaux :
Un autre intérêt de créer un secondaire depuis une sauvegarde PITR est de ne pas charger le serveur primaire : les fichiers sont copiés depuis le dépôt.
Il y a un petit inconvénient : la sauvegarde peut dater de plusieurs jours, donc il y aura plus de journaux à restaurer qu’en faisant une nouvelle copie du primaire. Dans le cas de pgBackRest, le mode « asynchrone » de restauration des journaux peut beaucoup accélérer les choses.
8.2.4 Pg_rewind
- Pour récupérer un primaire après bascule & divergence
- Évite la reconstruction complète
- Pré-requis :
- data_checksums = on
- ou wal_log_hints = on
- tous les WAL depuis la divergence
- full_page_writes = on (défaut)
- Revient au point de divergence
Le cas typique d’utilisation de pg_rewind est de résoudre la divergence entre un ancien primaire et le nouveau primaire après une bascule. Si la bascule n’a pas été propre, des informations ont été écrites sur l’ancien primaire, qui n’ont pas été transmises au nouveau avant la bascule. Cette divergence empêche de raccrocher simplement l’ancien primaire au nouveau comme secondaire : les enregistrements de journaux dont le LSN est postérieur à la promotion de l’ancien secondaire diffèrent entre les deux machines. Un autre cas est un secondaire ouvert brièvement en écriture par erreur, et qui a donc généré quelques entrées de journaux, et donc divergé de son primaire. Dans les deux cas, il faudrait en principe reconstruire le secondaire. Mais comme la divergence est courte, l’outil pg_rewind peut éviter cela. pg_rewind fait partie des outils livrés avec PostgreSQL. Sur l’instance, il nécessite soit la présence des checksums (qui doivent être mis en place à la création de l’instance, ou ajoutés instance arrêtée), soit l’activation du paramètre wal_log_hints , et tout cela suffisamment en avance avant la divergence. La volumétrie des journaux de transactions augmentera un peu. full_page_writes est aussi nécessaire, mais il est activé par défaut. Le serveur à récupérer doit être arrêté proprement. Si ce n’est pas le cas, pg_rewind le démarre en mode mono-utilisateur, puis l’arrête. Le serveur source (le nouveau primaire) doit être aussi arrêté proprement sur le même serveur, ou bien accessible par une connexion classique. L’utilisateur requis pour se connecter à la nouvelle primaire n’est pas forcément un superutilisateur. Le droit de se connecter ( LOGIN ) et d’exécuter les fonctions suivantes suffit : pg_ls_dir() , pg_stat_file() , pg_read_binary_file(text) et
pg_hba.conf utilisé pour une connexion de réplication classique ne suffit pas.
Sur l’instance à récupérer, pg_rewind analyse les journaux de transactions, depuis le checkpoint précédant la divergence jusqu’au moment où le serveur a été arrêté, pour y récupérer la liste des blocs modifiés. Les journaux à récupérer depuis le nouveau primaire doivent se trouver dans le répertoire pg_wal de l’instance à récupérer, à moins qu’une restore_command adéquate permette de récupérer les journaux manquants. pg_rewind récupère ensuite de la nouvelle instance primaire tous les blocs dont la liste a été générée
précédemment. Puis, il copie tous les autres fichiers, ce qui inclut ceux des nouvelles relations, les WAL, le contenu du répertoire pg_xact et les fichiers de configurations présents dans le répertoire de données. Seuls les fichiers habituellement exclus des sauvegardes ne sont pas récupérés. Pour finir, il crée un fichier backup_label et met à jour le LSN du dernier point de cohérence dans le control file. Une fois l’opération réalisée, l’instance est redémarrée et se met à rejouer tous les journaux depuis le point du dernier checkpoint précédant le point de divergence. Avant de redémarrer l’instance, il ne faut pas oublier de la configurer en tant que secondaire ( standby.signal , primary_conninfo …). L’outil a l’option –write-recovery.conf pour faire cela lui-même, mais il vaut mieux toujours contrôler. Notamment, pg_rewind ne peut pas savoir quel est le bon utilisateur à prendre pour la réplication. Documentation :
pg_rewind dans la documentation officielle 3
Source 3 : https://docs.postgresql.fr/current/app-pgrewind.html
8.3 Outils dédiés au log shipping & à la sauvegarde PITR
8.3.1 Réplication par log shipping sécurisée par la sauvegarde PITR
- Utilisation des archives pour :
- se prémunir du décrochage d’un secondaire
- une sauvegarde PITR
- Utilisation des sauvegardes PITR pour :
- resynchroniser un serveur secondaire
Une sauvegarde PITR est souvent mise en place en production : autant utiliser les journaux archivés pour sécuriser la réplication en streaming. Cela évite de rajouter un slot de réplication, ou permet de configurer un max_slot_wal_keep_size assez bas pour le slot. (À noter que la sécurisation par PITR ne concerne que la réplication physique. La réplication logique est basée sur le streaming et rend obligatoires des slots de réplication dédiés.) Il est aussi possible de se servir des sauvegardes PITR pour reconstruire un serveur secondaire plutôt que de réaliser la copie directement depuis l’instance principale.
8.3.2 PgBackRest
- pgbackrest restore
- –type=standby
- –recovery-option
- –delta (optionnel)
Il est possible d’utiliser certaines options (en ligne de commande ou fichier de configuration) de l’outil pgBackRest pour resynchroniser une instance secondaire à partir d’une sauvegarde PITR. Par exemple :
- –delta : ne recopiera que les fichiers dont la somme de contrôle ( checksum ) est différente entre la sauvegarde et le répertoire de destination, les fichiers qui ne sont pas présents dans la sauvegarde sont supprimés du répertoire de l’instance;
- –type=standby : crée le fichier standby.signal et ajoute la restore_command au fichier postgresql.auto.conf ;
- –recovery-option : permet de spécifier des paramètres particuliers pour la configuration de la restauration ( recovery_target_* …) ou de la réplication ( primary_conninfo …).
8.3.3 Barman
- barman recover
- –standby-mode
- –target-*
Il est possible d’utiliser certaines options de l’outil Barman pour resynchroniser une instance secondaire à partir d’une sauvegarde PITR. Par exemple :
- –standby-mode : crée le fichier standby.signal ; la restore_command peut également être ajoutée dans postgresql.auto.conf ;
- –target-* : permettent de spécifier des paramètres particuliers pour la configuration de la restauration ( recovery_target_* …).
8.4 Promotion automatique
Minimiser le temps d’interruption du service en cas d’avarie
8.4.1 Promotion automatique : vocabulaire
- SPOF : Single Point Of Failure
- Redondance : pour éviter les SPOF
- Ressources : éléments gérés par un cluster
- Split brain : deux primaires! et perte de données
- Fencing : isoler un serveur défaillant
- STONITH : Shoot The Other Node In The Head (voir Fencing)
- Watchdog : permet à un serveur de s’auto isoler
- Quorum : participe à la résolution des partitions réseau
Pour minimiser le temps d’interruption d’un service, il faut implémenter les éléments nécessaires à la tolérance de panne en se posant la question : que faire si le service n’est plus disponible ? Une possibilité s’offre naturellement : on prévoit une machine prête à prendre le relais en cas de problème. Lorsqu’on réfléchit aux détails de la mise en place de cette solution, il faut considérer :
- les causes possibles de panne;
- les actions à prendre face à une panne déterminée et leur automatisation;
- les situations pouvant corrompre les données. Les éléments de la plate-forme, aussi matériels que logiciels, dont la défaillance mène à l’indisponibilité du service, sont appelés SPOF dans le jargon de la haute disponibilité, ce qui signifie Single Point Of Failure ou point individuel de défaillance. L’objectif de la mise en haute disponibilité est d’éliminer ces SPOF. Ce travail concerne le service dans sa globalité : si le serveur applicatif n’est pas hautementdisponible alors que la base de données l’est, le service peut être interrompu car le serveur applicatif est un SPOF. On élimine les différents SPOF possibles par la redondance, à la fois matérielle, logicielle mais aussi humaine en évitant qu’une personne détienne toute la connaissance sur un sujet clé. Par la suite, on discutera de la complexité induite par la mise en haute disponibilité. En effet, dans le cas d’une base de données, éviter les corruptions lors d’événements sur le cluster est primordial. On peut se trouver dans une situation où les deux machines considèrent qu’elles sont le seul primaire de leur cluster (Split-Brain, avec écriture de données sur les deux serveurs simultanément, et la perspective d’une réconciliation délicate); ou bien entrent en concurrence pour un accès en écriture sur un même disque partagé. Pour se protéger d’une partition réseau, on peut utiliser un dispositif implémentant un Quorum. Chaque machine se voit allouer un poids qui sera utilisé lors des votes. En cas de coupure réseau, la
partition possédant le plus de votes a le droit de conserver les ressources actives, la ou les autres partitions doivent relâcher les ressources ou les éteindre. Pour éviter d’avoir des serveurs ou ressources dont l’état est inconnu ou incohérent (serveur injoignable ou ressource qui refuse de s’arrêter), on utilise le Fencing. Cette technique permet d’isoler une machine du cluster (« nœud ») en lui interdisant l’accès à certaines ressources ou en l’arrêtant. Cette deuxième solution est plus connue sous le nom de STONITH (Shoot The Other Node In The Head). Les techniques pour arriver à ce résultat varient : de la coupure de l’alimentation (PDU, IPMI), à la demande faite au superviseur d’arrêter une machine virtuelle. Une alternative est l’utilisation d’un Watchdog. Ce dispositif arrête le serveur s’il n’est pas réarmé à intervalle régulier, ce qui permet à un serveur de s’isoler lui-même. Pour finir, il est possible d’utiliser un dispositif appelé SBD (Storage Based Death) qui combine ces concepts et outils (fencing et watchdog). Un stockage partagé permet aux serveurs de communiquer pour signaler leur présence ou demander l’arrêt d’un serveur. Si un serveur n’a plus accès au disque partagé, il doit arrêter ses ressources ou s’arrêter si c’est impossible. Une solution de haute disponibilité robuste combine ces mécanismes pour un maximum de fiabilité.
8.4.2 Patroni
- Outil de HA
- Basé sur un gestionnaire de configuration distribué : etcd, Consul, ZooKeeper…
- Contexte physique, VM ou container
- Spilo : image docker PostgreSQL+Patroni
Patroni 4 est un outil de HA développé par Zalando, nécessitant un gestionnaire de configuration distribué (appelé DCS) tel que ZooKeeper, etcd ou Consul. Le daemon Patroni fait le lien entre le quorum fourni par le DCS, l’éventuelle utilisation d’un module watchdog, la communication avec les autres nœuds Patroni du cluster et la gestion complète de l’instance PostgreSQL locale : de son démarrage à son arrêt. Le watchdog est un mécanisme permettant de redémarrer le serveur en cas de défaillance. Il est ici utilisé pour redémarrer si le processus Patroni n’est plus disponible (crash, freeze, bug, etc). Zalando utilise Patroni principalement dans un environnement conteneurisé. À cet effet, ils ont packagé PostgreSQL et Patroni dans une image docker : Spilo 5 . Cependant, Patroni peut tout à fait être déployé en dehors d’un conteneur, sur une machine physique ou virtuelle. Une formation Dalibo complète existe sur Patroni : https://dali.bo/hapat
- Source 4 : https://github.com/zalando/patroni
- Source 5 : https://github.com/zalando/spilo
8.4.3 Repmgr
- Outil spécialisé PostgreSQL
- En pratique, fiable pour 2 nœuds
- Gère automatiquement la bascule en cas de problème
- health check
- failover et switchover automatiques
- Witness
L’outil repmgr 6 de 2ndQuadrant permet la gestion de la haute disponibilité avec notamment la gestion des opérations de clonage, de promotion d’une instance en primaire et la démotion d’une instance.
L’outil repmgr peut également être en charge de la promotion automatique du nœud secondaire en cas de panne du nœud primaire, cela implique la mise en place d’un serveur supplémentaire par cluster HA (paire primaire/secondaire) appelé témoin (witness). Cette machine héberge une instance PostgreSQL dédiée au processus daemon repmgrd , processus responsable d’effectuer les contrôles d’accès réguliers à l’instance primaire et de promouvoir le nœud secondaire lorsqu’une panne est détectée et confirmée suite à plusieurs tentatives échouées consécutives.
Afin de faciliter la bascule du trafic sur l’instance secondaire en cas de panne du primaire, l’utilisation d’une adresse IP virtuelle (VIP) est requise. Les applications clientes (hors administration) doivent se connecter directement à la VIP.
8.4.4 Pacemaker
- Solution de Haute Disponibilité généraliste
- Disponible sur les distributions les plus répandues
- Se base sur Corosync, un service de messagerie inter-nœuds
- Permet de surveiller la disponibilité des machines
- Gère le quorum, le fencing, le watchdog et le SBD
- Gère les ressources d’un cluster et leur interdépendance
- Extensible
Pacemaker associe la surveillance de la disponibilité de machines et d’applications. Il offre l’outillage nécessaire pour effectuer les actions suite à une panne. Il s’agit d’une solution de haute disponibilité extensible avec des scripts.
- Source 6 : https://www.repmgr.org/
8.4.5 Paf
- Postgres Automatic Failover
- Ressource Agent pour Pacemaker et Corosync permettant de :
- détecter un incident
- relancer l’instance primaire
- basculer sur un autre nœud en cas d’échec de relance
- élire le meilleur secondaire (avec le retard le plus faible)
- basculer les rôles au sein du cluster en primaire et secondaire
- Avec les fonctionnalités offertes par Pacemaker & Corosync :
- surveillance de la disponibilité du service
- quorum & Fencing
- gestion des ressources du cluster
PAF est le fruit de la R&D de Dalibo visant à combler les lacunes des agents existants. Il s’agit d’un produit opensource, disponible sur ce dépôt 7 et qui a rejoint la communauté ClusterLabs qui gère aussi Pacemaker.
- Source 7 : https://clusterlabs.github.io/PAF/
8.5 Conclusion
De nombreuses applications tierces peuvent nous aider à administrer efficacement un cluster en réplication.
8.5.1 Questions
N’hésitez pas, c’est le moment !
8.6 Travaux pratiques
La version en ligne des solutions de ces TP est disponible sur https://dali.bo/w3_solutions.
Pour ces travaux pratiques, procéder à :
- la promotion de l’instance instance2;
- la reconstruction de l’ancienne instance primaire via pg_rewind ;
- la sauvegarde de l’instance instance2 avec pgBackRest;
- la promotion “par erreur” de l’instance instance3;
- la reconstruction de l’instance instance3 en se servant des sauvegardes pgBackRest.
8.6.1 (Pré-requis) Environnement
Pour ces TP vous devez avoir 3 instances (1 primaire, 2 secondaires en réplication). Au besoin, repasser en réplication asynchrone en désactivant le paramètre synchronous_standby_names de l’instance primaire.
PID CMD 3205 /usr/pgsql-14/bin/postmaster -D /var/lib/pgsql/14/instance3/ 3207_ postgres: logger 3208_ postgres: startup recovering 000000030000000000000038 3212_ postgres: checkpointer 3213_ postgres: background writer 3215_ postgres: stats collector 3216_ postgres: walreceiver streaming 0/38000060 3144 /usr/pgsql-14/bin/postmaster -D /var/lib/pgsql/14/instance2/ 3146_ postgres: logger 3147_ postgres: startup recovering 000000030000000000000038 3151_ postgres: checkpointer 3152_ postgres: background writer 3154_ postgres: stats collector 3155_ postgres: walreceiver streaming 0/38000060 2896 /usr/pgsql-14/bin/postmaster -D /var/lib/pgsql/14/instance1/ 2898_ postgres: logger 2900_ postgres: checkpointer 2901_ postgres: background writer 2902_ postgres: walwriter 2903_ postgres: autovacuum launcher 2904_ postgres: archiver last was 000000030000000000000037.00000028.backup 2905_ postgres: stats collector 2906_ postgres: logical replication launcher 3156_ postgres: walsender repli 127.0.0.1(47494) streaming 0/38000060 3217_ postgres: walsender repli 127.0.0.1(47502) streaming 0/38000060
flush_lsn, replay_lsn, sync_state FROM pg_stat_replication;"
-[ RECORD 1 ]—-+———–
Pour utiliser pg_rewind , il faut s’assurer que l’instance a été créée avec l’option –data-checksums . Dans le cas contraire, il faut activer wal_log_hints = on dans le postgresql.conf . Pour vérifier les valeurs en cours, exécuter en SQL !
ou utiliser l’outil shell pg_controldata :
Data page checksum version: 0
Par défaut, une instance est initialisée sans sommes de contrôle. Nous devons donc configurer le paramètre wal_log_hints à la valeur on . Lançons un checkpoint afin de s’assurer que les nouveaux journaux contiendrons les hints bits :
Si vous avez suivi correctement les travaux pratiques précédents, vous avez activé les checksums et obtenez donc le résultat suivant :
Data page checksum version: 1
8.6.2 Promotion d’une instance secondaire
But : Réaliser la promotion d’une instance secondaire. Contrôler que l’archivage est bien configuré sur l’instance instance2.
Arrêter l’instance principale pour promouvoir l’instance instance2.
Vérifier le répertoire d’archivage. Que contient-il?
8.6.3 Suivi de timeline
But : Comprendre la relation entre timeline et réplication. Nous avons donc :
l’ancienne instance primaire arrêtée;
l’instance instance2 promue;
l’instance instance3 qui est toujours secondaire de l’instance primaire arrêtée. Nous allons tenter de raccrocher l’instance instance3 au nouveau primaire.
Configurer instance3 pour qu’il se connecte au instance2.
Observer les traces de l’instance : que se passe-t-il?
8.6.4 Pg_rewind
But : « rembobiner » un ancien primaire avec pg_rewind . Nous allons maintenant expérimenter le cas où l’instance primaire n’a pas été arrêtée avant la bascule. Il peut donc y avoir des transactions dans la timeline 2 qui n’existent pas dans la timeline 3 ce qui rend impossible la mise en réplication avec le instance2. Comme décrit plus haut, pour utiliser pg_rewind , il faut s’assurer que l’instance a été créée avec l’option –data-checksums ou que le paramètre wal_log_hints est à on .
Redémarrer l’ancienne instance primaire (instance1).
Y créer une table t7 . Dans quelle timeline existe-t-elle?
Créer une table t8 sur instance2.
Arrêter instance1.
La resynchroniser avec instance2 à l’aide de pg_rewind .
Ne pas oublier de vérifier les fichiers de configuration.
Configurer cette instance resynchronisée en réplication depuis l’instance instance2.
Ne pas démarrer.
Démarrer. Observer les traces. Qu’est-il advenu des données insérées avant l’utilisation de pg_rewind ?
Vérifier que instance2 est bien le serveur principal des deux autres instances.
8.6.5 PgBackRest
But : Utiliser pgBackRest dans le cadre de la réplication.
Configurer pgBackRest pour sauvegarder votre nouvelle instance principale (instance2).
Effectuer une sauvegarde initiale.
Insérer des données et vérifier que des archives ont bien été générées.
Effectuer une promotion « par erreur » du serveur instance3, et y insérer des données.
Resynchroniser l’instance secondaire instance3 à l’aide de la sauvegarde de pgBackRest.
Vérifier enfin que la réplication entre instance3 et instance2 a bien repris.
8.7 Travaux pratiques (solutions)
8.7.1 (Pré-requis) Environnement
Pour ces TP vous devez avoir 3 instances (1 primaire, 2 secondaires en réplication). Au besoin, repasser en réplication asynchrone en désactivant le paramètre synchronous_standby_names de l’instance primaire.
PID CMD 3205 /usr/pgsql-14/bin/postmaster -D /var/lib/pgsql/14/instance3/ 3207_ postgres: logger 3208_ postgres: startup recovering 000000030000000000000038 3212_ postgres: checkpointer 3213_ postgres: background writer 3215_ postgres: stats collector 3216_ postgres: walreceiver streaming 0/38000060 3144 /usr/pgsql-14/bin/postmaster -D /var/lib/pgsql/14/instance2/ 3146_ postgres: logger 3147_ postgres: startup recovering 000000030000000000000038 3151_ postgres: checkpointer 3152_ postgres: background writer 3154_ postgres: stats collector 3155_ postgres: walreceiver streaming 0/38000060 2896 /usr/pgsql-14/bin/postmaster -D /var/lib/pgsql/14/instance1/ 2898_ postgres: logger 2900_ postgres: checkpointer 2901_ postgres: background writer 2902_ postgres: walwriter 2903_ postgres: autovacuum launcher 2904_ postgres: archiver last was 000000030000000000000037.00000028.backup 2905_ postgres: stats collector 2906_ postgres: logical replication launcher 3156_ postgres: walsender repli 127.0.0.1(47494) streaming 0/38000060 3217_ postgres: walsender repli 127.0.0.1(47502) streaming 0/38000060
flush_lsn, replay_lsn, sync_state FROM pg_stat_replication;"
Pour utiliser pg_rewind , il faut s’assurer que l’instance a été créée avec l’option –data-checksums . Dans le cas contraire, il faut activer wal_log_hints = on dans le postgresql.conf . Pour vérifier les valeurs en cours, exécuter en SQL !
ou utiliser l’outil shell pg_controldata :
Data page checksum version: 0
Par défaut, une instance est initialisée sans sommes de contrôle. Nous devons donc configurer le paramètre wal_log_hints à la valeur on . Lançons un checkpoint afin de s’assurer que les nouveaux journaux contiendrons les hints bits :
Si vous avez suivi correctement les travaux pratiques précédents, vous avez activé les checksums et obtenez donc le résultat suivant :
Data page checksum version: 1
8.7.2 Promotion d’une instance secondaire
Contrôler que l’archivage est bien configuré sur l’instance instance2.
Avec archive_mode à on , seule l’instance primaire effectue l’archivage des journaux de transaction. Arrêter l’instance principale pour promouvoir l’instance instance2.
Dans les traces, nous trouvons ceci :
Le serveur a bien reçu la demande de promotion, ensuite (si restore_command est spécifié) il cherche à rejouer les derniers journaux de transaction depuis les archives. Puis il vérifie la présence d’un fichier 00000003.history pour déterminer une nouvelle timeline.
Une fois ces opérations effectuées, il détermine la nouvelle timeline (ici, 4) et devient accessible en lecture/écriture :
Vérifier le répertoire d’archivage. Que contient-il?
Vu que le paramètre archive_mode était à on , seul le serveur primaire effectuait l’archivage. En effectuant la promotion de l’instance instance2, celle-ci est devenue primaire et archive donc vers le même répertoire! Il y a bien un archiver process :
Le répertoire d’archive contient :
(…) -rw——-. 1 postgres postgres 16M Nov 28 16:06 000000030000000000000039.partial -rw——-. 1 postgres postgres 84 Nov 28 16:06 00000004.history (…)
Le serveur a archivé le dernier journal avec le suffixe .partial : ceci afin d’éviter d’écraser un fichier journal si le primaire était toujours actif. Avant la version 9.5, il pouvait y avoir un conflit entre l’ancien primaire et le secondaire promu archivant au même emplacement. Le fichier 00000003000000000000002F aurait pu être écrasé. Voir : Archiving of last segment on timeline after promotion http://paquier.xyz/postgresql-2/postgres-9-5-feature-highlight-partial-segmenttimeline/.
8.7.3 Suivi de timeline
- Configurer instance3 pour qu’il se connecte au instance2.
- Observer les traces de l’instance : que se passe-t-il?
Dans les traces de instance3 : 2019-11-28 16:13:17.328 CET [3876] FATAL: could not connect to the primary server: could not connect to server: Connection refused Is the server running on host “127.0.0.1” and accepting TCP/IP connections on port 5432?
Le serveur ne sait pas que l’instance instance2 a été promue, il constate juste que l’instance primaire a été arrêtée. Modifions le paramètre primary_conninfo de l’instance instance3 pour pointer vers l’instance instance2 :
Après redémarrage de l’instance, on peut constater que la modification s’est appliquée sur la timeline : (…) LOG:database system is ready to accept read only connections LOG:started streaming WAL from primary at 0/2F000000 on timeline 4 LOG:redo starts at 0/390000A0
La table t6 existe bien et contient bien les enregistrements :
c1 —- 1
8.7.4 Pg_rewind
- Redémarrer l’ancienne instance primaire (instance1).
- Y créer une table t7 . Dans quelle timeline existe-t-elle?
Créons la table t7 sur instance1 :
- Créer une table t8 sur instance2.
Créons la table t8 sur instance2 :
La table t7 existe dans la timeline 3 mais pas dans la timeline 4. Nous allons donc utiliser l’outil pg_rewind . Il ne lit et ne copie que les données modifiées. L’outil identifie les blocs correspondants aux transactions « perdues ». Dans notre exemple, la table t7 n’est présente que sur la nouvelle instance. Ensuite il copie les blocs correspondants sur l’instance cible.
- Arrêter instance1.
- La resynchroniser avec instance2 à l’aide de pg_rewind .
- Ne pas oublier de vérifier les fichiers de configuration.
- Configurer cette instance resynchronisée en réplication depuis l’instance instance2.
- Ne pas démarrer.
Maintenant passons à pg_rewind . L’option -n permet d’effectuer un test sans modification :
On relance la commande sans l’option -n :
On constate qu’il a juste été nécessaire de copier 101 Mo au lieu des 370 Mo de l’instance complète. pg_rewind se connecte sur le serveur source et identifie le point de divergence. Ensuite, il liste les fichiers à copier ou supprimer. Puis il copie les blocs modifiés. Enfin il met à jour le fichier backup_label et le fichier pg_control.
Les fichiers postgresql.conf et postgresql.auto.conf provenant du instance2, il faut modifier le port ainsi que le primary_conninfo :
Créer le fichier standby.signal :
Et démarrer l’instance :
- Démarrer. Observer les traces. Qu’est-il advenu des données insérées avant l’utilisation de pg_rewind ?
Dans les traces :
La table t7 a bien disparu de l’instance resynchronisée :
- Vérifier que instance2 est bien le serveur principal des deux autres instances.
8.7.5 PgBackRest
- Configurer pgBackRest pour sauvegarder votre nouvelle instance principale (instance2).
Commencer par modifier :
Ensuite, recharger la configuration :
Modifier ensuite la configuration de pgBackRest dans /etc/pgbackrest.conf :
[instance_dev]
Vérifier que le répertoire où les archives et les sauvegardes seront stockées est bien vide ( /var/lib/pgsql/14/backups/ ). Initialiser le dépôt de pgBackRest et vérifier que l’archivage est fonctionnel :
P00 INFO: stanza-create command begin 2.20: –log-level-console=info
P00 INFO: stanza-create command end: completed successfully (463ms)
P00 INFO: check command begin 2.20: –log-level-console=info
P00 INFO: WAL segment 000000040000000000000039 successfully archived to ‘/var/lib/pgsql/14/backups/archive/instance_dev/14-1/0000000400000000/ 000000040000000000000039-9b054265590ac75cd70ba3ed5b1f47c113a69b84.gz’ P00 INFO: check command end: completed successfully
- Effectuer une sauvegarde initiale.
- Insérer des données et vérifier que des archives ont bien été générées.
Pour une première sauvegarde :
P00 INFO: backup command begin 2.20: –log-level-console=info
P00 INFO: execute non-exclusive pg_start_backup() with label “…”: backup begins after the requested immediate checkpoint completes P00 INFO: backup start archive = 00000004000000000000003B, lsn = 0/3B000060 P00 INFO: full backup size = 274.2MB P00 INFO: execute non-exclusive pg_stop_backup() and wait for all WAL segments to archive P00 INFO: backup stop archive = 00000004000000000000003B, lsn = 0/3B000138 P00 INFO: new backup label = 20200110-081833F P00 INFO: backup command end: completed successfully P00 INFO: expire command begin 2.20: –log-level-console=info
P00 INFO: expire command end: completed successfully
Insérer des données :
Forcer la génération d’un nouveau WAL et vérifier que des archives ont bien été générées :
0/3FD474E8
last_archived_wal
00000004000000000000003F
- Effectuer une promotion « par erreur » du serveur instance3, et y insérer des données.
- Resynchroniser l’instance secondaire instance3 à l’aide de la sauvegarde de pgBackRest.
De nouvelles données ayant été écrites, nous devons désormais reconstruire l’instance instance3 pour pouvoir la remettre en réplication avec instance2. Pour ce faire, nous pourrions utiliser comme précédemment. Nous allons ici utiliser les sauvegardes pgBackRest pour
reconstruire l’instance. La sauvegarde de l’instance primaire peut être restaurée sur la seconde instance avec les options
dans le répertoire de données. pgBackRest se charge de configurer les options de réplication dans le fichier postgresql.auto.conf .
P00 INFO: restore command begin 2.20: –delta –log-level-console=info
- Vérifier enfin que la réplication entre instance3 et instance2 a bien repris.
Modifier le port de l’instance instance3 avant de la démarrer et vérifier que la connexion de réplication est bien fonctionnelle :