Réplication par transfert de journaux de transaction – Part 2

Dans cet article nous allons aborder la réplication par transfert de journaux de transaction. Dans le précédent article j’ai expliqué que ce qui faisait la cohérence d’une base c’était les fichier de la base (contenus dans le répertoire base) et les journaux de transaction (pg_xlogs). La réplication la plus simple consiste à partir d’une base de départ puis de rejouer les journaux de transactions.

Je vais partir d’une installation debian de base (netinstall minimale), puis nous allons installer Posgres. Nous l’alimenterons avec pgbench. Ensuite nous installerons un second serveur Postgres qui sera le réplicat.

Installation du Master

Installation debian netinstall minimale (avec serveur SSH). Pour ce TP sur la réplication j’ai fait très simple, tout est dans une seule partition. A ne pas faire sur des environnements de production! C’est indispensable de séparer les fichiers du système d’exploitation, les fichiers de base et les journaux de transaction.

Une fois que notre debian est prête il faut ajouter le dépôt Postgres : http://www.postgresql.org/download/linux/debian/

  • Create the file /etc/apt/sources.list.d/pgdg.list, and add a line for the repository deb http://apt.postgresql.org/pub/repos/apt/ wheezy-pgdg main
  • Import the repository signing key, and update the package lists wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | \
    apt-key add -
    apt-get update

Un « aptitude search postgres » nous donne les versions de Postgres suivantes : 8.2, 8.3, 8.4, 9.1, 9.2, 9.3, 9.4.
Nous allons utiliser la 9.3 correspondant à la dernière version stable.

 aptitude install postgresql-9.3 postgresql-contrib-9.3

Durant l’installation vous verrez apparaitre ces lignes :

Chez Debian les fichiers de configuration sont dans /etc/postgresql/9.3/main , les données : /var/lib/postgresql/9.3/main

Test de connexion à l base :

 

Installation du Slave

Reprendre la même procédure que pour le Master

 

Création base pgbench

Nous allons utiliser l’outil pgbench. Il faut initialiser la base pgbench.  Nous allons spécifier le scaling factor (-s) à 50 pour avoir une base de taille raisonnable (autour de 700Mo) :

pgbench -i -h /var/run/postgresql/ -U postgres -s 50

Un petit test pour vérifier que tout fonctionne :

Un autre test plus évolué :

 

Archivage des WAL

Nous allons mettre en place l’archivage des journaux de transaction. C’est assez simple, dans postgres.conf nous allons indiquer à postgres quelle commande exécuter lorsqu’il a fini d’écrire un fichier journal. J’aime cette façon de procéder chez postgres. C’est très simple, postgres exécute une commande, après libre à l’administrateur de faire une simple copie et d’écrire un script plus évolué.

Nous allons utiliser la commande rsync. L’intérêt d’utiliser rsync est qu’il crée un fichier temporaire et une fois la copie terminée ils renomme le fichier.

Dans le fichier postgres.conf il y a une section « WRITE AHEAD LOG »

Il faut spécifier les lignes suivantes :

 

Le paramètre archive_timeout permet de forcer la rotation de journal toutes les 300 secondes. En effet s’il y a peu d’activité sur votre base le délai entre deux journaux pourrait être important, ce délai correspond au delta entre le maitre et l’esclave donc la perte de donnée que vous auriez.  En forçant une rotation toutes les 300 secondes, la perte de données maximale serait de 300 secondes.

Sur le slave nous allons créer le répertoire qui va contenir les journaux archivés :

mkdir /var/lib/postgresql/9.3/wal_archive

Bien penser à changer le propriétaire du répertoire :

chown postgres:postgres /var/lib/postgresql/9.3/wal_archive

Pour que le rsync fonctionne il faut procéder à un échange de clé :

Sur le maître :

ssh-keygen -t rsa -C postgres-key

Déplacer la clé générée dans le home de postgres :

mv /root/.ssh /var/lib/postgresql

Bien penser à changer les droits :

chown -R postgres:postgres /var/lib/postgresql/.ssh

Sur l’esclave, créer le répertoire qui va contenir les clés :

Lancer la copie depuis le maître :

scp /var/lib/postgresql/.ssh/id_rsa.pub root@pg-slave:/var/lib/postgresql/.ssh/authorized_keys

Ensuite sur le maitre, passer en user postgres et tester la connexion :

A la première connexion ssh va demander une validation de la clé puis vous connecte sur le serveur esclave. S’il vous demande un mot de passe c’est que l’échange de clé ne fonctionne pas.

Lancer une copie de test :

Maintenant on peut relancer le postgres Maitre et constater que les journaux se copient bien :

 

Création réplicat

Sur le réplicat, stopper postgres et lancer la copie du maitre vers le réplicat :

On conserve l’ancienne instance :

mv /var/lib/postgresql/9.3/main /var/lib/postgresql/9.3/main.old

Sur le Master on lance la commande pg_start_backup() qui va déclencher un checkpoint et laisser une marque dans les journaux de transaction.

select pg_start_backup('backup-replicat',true);

On lance la copie :

rsync -a root@pg-master:/var/lib/postgresql/9.3/main /var/lib/postgresql/9.3/

Quand la copie est terminée lancer un pg_stop_backup :

select pg_stop_backup();

Vous remarquerez que nous avons effectué une copie des fichier sans arrêter le serveur maître.

Supprimer les fichiers du répertoire pg_xlog :

rm pg_xlog/* postmaster.pid pg_log/* -rf

Ne pas lancer postgres! Maintenant il faut configurer le fichier recovery.conf pour indiquer à postgres qu’il est en mode restauration.

Créer le fichier recovery.conf dans le répertoire/var/lib/postgresql/9.3/main/

On restaure les droits :

 chown -R postgres:postgres main

On peut enfin lancer postgres et voir dans les logs :

Note : On voit dans les logs la ligne suivante apparaitre :

cp: cannot stat `/var/lib/postgresql/9.3/wal_archive/000000010000000000000034′: No such file or directory

Postgres fait régulièrement appel à la « restore_command ». Quand cp ne trouve pas de fichier il retourne une erreur.

Mais au bout de 5min on voit la ligne suivante :

Ces 5min correspondent au paramètre « archive_timeout » que nous avons positionné à 300 secondes.

Explications

pg_start_backup

Pour résumer, nous venons de mettre en place une archivage des journaux de transaction sur le maitre, le secondaire est configuré pour rejouer en permanence les WAL qui arrivent dans son dossier wal_archive.

Nous avons utilisé les commandes pg_start_backup et pg_stop_backup. pg_start_backup va créer un fichier backup_label :

START WAL LOCATION: 0/4A000028 (file 00000001000000000000004A)
CHECKPOINT LOCATION: 0/4A000028
BACKUP METHOD: pg_start_backup
BACKUP FROM: master
START TIME: 2014-11-09 19:52:49 CET
LABEL: label

Ce fichier indique le label que nous avons passé à la commande et surtout le checkpoint. En effet, lorsque pg_start_backup est exécuté il va attendre un checkpoint sinon il est possible de forcer le checkpoint en ajoutant l’option ‘true’.

Durant la copie les données ont pu être modifiée, ce n’est pas grave car toute modification a été écrite dans les journaux de transaction.  A l’issue de la copie nous avons lancé pg_stop_backup, cette commande va supprimer le fichier backup_label et laisser une marque dans les journaux de transaction :

Coté esclave on peut remarquer que le répertoire d’archivage contient :

 

On retrouve le checkpoint de départ : 0/4A000028
Le moment où on a lancé pg_stop_backup : 0/4B0000B8

L’option  standby_mode = ‘on’ dans le fichier recovery.conf indique à postgres qu’il doit rejouer en permanence les journaux de transaction, si elle était absente postgres se serait contenté de rejouer les journaux de transaction jusqu’au point STOP WAL LOCATION: 0/4B0000B8

Exemple :

Sur le maitre :

Copie des fichiers avec rsync

On lance le postgres esclave sans la ligne standby_mode :

On remarque que postgres renomme le fichier recovery.conf en recovery.done et qu’il écoute les connections. La restauration se fait au point du pg_stop_backup : « consistent recovery state reached at 0/500000B8 ».

Pratique pour créer une copie d’un serveur en production ou pour faire une sauvegarde.

Processus lancés

On remarque que le process wal writer n’est pas lancé, il n’a aucun intérêt car en recovery mode il n’y aucun journal de transaction à écrire.

Fichiers journaux sur l’esclave

Quand l’esclave a joué un WAL il créé un fichier du même nom avec le suffixe .done dans le répertoire archive_status.

Impossiblité d’archiver les WAL

Si le maitre n’arrive plus à envoyer les journaux de transaction :

Nettoyage des WAL archivés

On peut choisir de supprimer manuellement les WAL archivés sinon on peut utiliser l’outil pg_archivecleanup. Il faut rajouter l’option archive_cleanup_command dans le fichier recovery.conf :

archive_cleanup_command = '/usr/lib/postgresql/9.3/bin/pg_archivecleanup  /var/lib/postgresql/9.3/wal_archive/ %r'

L’option -d permet d’avoir plus d’information :

archive_cleanup_command = '/usr/lib/postgresql/9.3/bin/pg_archivecleanup -d /var/lib/postgresql/9.3/wal_archive/ %r'

Malgrès ce nettoyage on remarque qu’il reste encore beaucoup de fichiers dans le répertoire d’archivage. En réalité postgres copie plusieurs journaux avant de les rejouer. Dans les logs on distingue bien ce comportement :

Erreurs « unexpected pageaddr »

On remarque les lignes suivantes dans les logs:

2014-11-09 20:53:33 CET LOG:  unexpected pageaddr 0/53000000 in log segment 000000010000000000000058, offset 0

Je n’ai pas trouvé d’explication simple pour ce message. Mes recherches sur internet indiquent qu’on peut ignorer cette erreur, les événements « LOG » sont juste informatifs.

Share

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *