lundi 21 février 2011

Réplication “temps réel” d’une base Postgresql

 

Objectif

La base de données d’une application est un composant sensible, surtout si l’application est une application métier en production.

De nombreux mécanismes peuvent (et doivent) être mis en place pour garantir une disponibilité de la base de données :

  1. Utilisation de disques en RAID pour prévenir les défaillances matérielles
  2. Sauvegarde (quotidienne) sur support externalisé (et bien sur vérification régulière de la restauration de ces supports)

Ces mécanismes ne sont pas à mon sens suffisants. En effet, si la base de données pour une raison ou une autre, est corrompue, soit les sauvegardes seront corrompues, soit la dernière sauvegarde sera correcte, mais l’on perd alors jusqu’à une journée de données.

Pour améliorer la sécurité, il est ainsi nécessaire de mettre en place un mécanisme de réplication “temps réel” de notre base de données. Ce mécanisme doit permettre de “remonter” la base de données à un moment dans le temps défini. Ainsi, si notre base a été corrompue à 13h05, il sera possible de remonter la base à 13h00, et de ne perdre qu’un minimum d’informations métier.

Ce mécanisme s’appelle “PITR” pour “Point In Time Recovery”.

Avec postgresql, c’est très simple à mettre en oeuvre. Il nécessite toutefois un deuxième serveur de base de données, qui sera prêt à reprendre la main en cas de chute du premier.

Mécanisme

Le mécanisme proposé par postgresql est assez simple : toutes les transactions effectuées sur la base de production sont stockées dans des fichiers de transaction (“pg_xlogs”). Une fois un fichier log rempli, il est envoyé sur le serveur de secours. Le serveur de secours peut être configuré de deux façons différentes : soit il intègre immédiatement les fichiers reçus, soit il ne fait rien et l’intégration est déclenchée manuellement en cas de besoin.

Ainsi la notion de “temps réel” est relative : en cas de crash de la base de données, on ne pourra remonter que jusqu’au dernier fichier de transaction qui a été envoyé au serveur de secours. Les fichiers étant envoyés quand ils sont remplis, on a un délai un peu aléatoire avec les paramètres par défaut. Il est toutefois possible de définir : la taille des fichiers (par défaut 16M), et le temps maximum entre deux créations de fichiers. Ces paramètres ne sont pas détaillés dans ce billet.

Détail de la mise en place

Bien, après toutes ces explications, passons à la mise en oeuvre, c’est plus rapide que d’expliquer les choses :

Serveur de production

Il suffit de dire au serveur de production d’activer l’archivage des fichiers logs de transaction (postgresql.conf) :

# - Archiving -
archive_mode = on
archive_command = 'scp -C %p 10.1.1.241:/data/Rescue/%p'

Comme je choisi de ne pas intégrer régulièrement les fichiers de transaction dans le serveur de secours, il faut ajouter un mécanisme qui va permettre de faire le ménage des fichiers logs sur le serveur de secours. Il faut pour cela, sauvegarder régulièrement la base de données depuis le serveur de production vers le serveur de secours. Cette sauvegarde effectuée, on pourra faire le ménage sur le serveur de secours. Il suffit de créer le petit script suivant qui sera lancé par cron tous les jours sur le serveur de production.

# On informe le serveur de prod que l'on passe en mode backup
echo "SELECT pg_start_backup('
backupPostgres');" | psql -U postgres [base a sauver]
# Sauvegarde de la base vers le serveur de secours
rsync -avzx --delete --exclude '
pg_xlog' /data/db [serveur de secours]:/data
# On informe le serveur de prod que la sauvegarde est terminée
echo "SELECT pg_stop_backup();" | psql -U postgres [base a sauver]
# On lance le nettoyage sur le serveur de secours
ssh [serveur de secours] "/root/bin/nettoyageBackups.sh"


Serveur de secours


Sur le serveur de secours, il n’y a pas grand chose à faire… Il faut juste préparer le script de nettoyage des logs inutiles (appelé par le script précédent) :


# Nettoyage des pg_xlogs plus anciens que le dernier dump de la base
find /data/Rescue/pg_xlog ! -newer `ls /data/Rescue/pg_xlog/*.backup | sort | tail -n 1` ! -name "*.backup" | xargs rm -f


Attention, sur le serveur de secours, postgresql doit être arrêté. En effet, on ne veut pas qu’il intègre au fur et à mesure les fichiers de transaction. Cela permettra de contrôler en cas de crash, jusqu’où les fichiers sont intégrés.


Et maintenant ?


Bien, la sauvegarde est en place, mais en cas de crash que fait-on ?


Serveur de secours


C’est, encore une fois, très très simple : il suffi de démarrer postgresql sur le serveur de secours, en lui disant d’intégrer les fichiers de transaction qui sont en attente.


Pour passer le serveur en mode ‘intégration des fichiers de transactions’ :


# nettoyage vieux pg_xlogs qui pouvaient trainer dans le repertoire de la base
rm -f /data/db/pg_xlog/0000*
# creation du fichier recovery.conf pour que postgres
# demarre en mode recovery
cat >/data/db/recovery.conf <<EOF
restore_command = 'cp /data/Rescue/pg_xlog/%f %p'
EOF

Puis, on redémarre postgresql : /etc/init.d/postresql start

Attention : on ne voit pas que la réintégration est en cours. Pour vérifier que cela fonctionne, il suffit de faire un tail -f /data/db/pg_log/[dernier log du serveur]

Une fois le recovery fini, le fichier "/data/db/recovery.conf" est renommé automatiquement en "/data/db/recovery.done"

Pour arrêter l’intégration des fichiers logs à une certaine heure, il suffit de supprimer (déplacer) les fichiers que l’on ne veut pas intégrer du répertoire /data/Rescue/pg_xlogs


Mots clés Technorati : ,,,

Aucun commentaire:

Enregistrer un commentaire