Réplication de bases de données PostgreSQL avec Slony

Réplication de bases de données PostgreSQL avec Slony

Introduction à la haute disponibilité

Des serveurs de bases de données peuvent travailler ensemble pour permettre à un serveur secondaire de prendre rapidement la main si le serveur principal échoue (haute disponibilité, ou high availability), ou pour permettre à plusieurs serveurs de servir les mêmes données (répartition de charge, ou load balancing). Idéalement, les serveurs de bases de données peuvent travailler ensemble sans jointure.

Il est aisé de faire coopérer des serveurs web qui traitent des pages web statiques en répartissant la charge des requêtes web sur plusieurs machines. Dans les faits, les serveurs de bases de données en lecture seule peuvent également coopérer facilement. Malheureusement, la plupart des serveurs de bases de données traitent des requêtes de lecture/écriture et, de ce fait, collaborent plus difficilement. En effet, alors qu’il suffit de placer une seule fois les données en lecture seule sur chaque serveur, une écriture sur n’importe quel serveur doit, elle, être propagée à tous les serveurs afin que les lectures suivantes sur ces serveurs renvoient des résultats cohérents.

Ce problème de synchronisation représente la difficulté fondamentale à la collaboration entre serveurs. Comme la solution au problème de synchronisation n’est pas unique pour tous les cas pratiques, plusieurs solutions co-existent. Chacune répond de façon différente et minimise cet impact au regard d’une charge spécifique.

Certaines solutions gèrent la synchronisation en autorisant les modifications des données sur un seul serveur. Les serveurs qui peuvent modifier les données sont appelés serveur en lecture/écriture, maître ou serveur primaire. Les serveurs qui suivent les modifications du maître sont appelés standby, ou serveurs esclaves. Un serveur en standby auquel on ne peut pas se connecter tant qu’il n’a pas été promu en serveur maître est appelé un serveur en warm standby, et un qui peut accepter des connections et répondre à des requêtes en lecture seule est appelé un serveur en hot standby.

Certaines solutions sont synchrones, ce qui signifie qu’une transaction de modification de données n’est pas considérée valide tant que tous les serveurs n’ont pas validé la transaction. Ceci garantit qu’un failover ne perd pas de données et que tous les serveurs en répartition de charge retournent des résultats cohérents, quel que soit le serveur interrogé. Au contraire, les solutions asynchrones autorisent un délai entre la validation et sa propagation aux autres serveurs. Cette solution implique une éventuelle perte de transactions lors de la bascule sur un serveur de sauvegarde, ou l’envoi de données obsolètes par les serveurs à charge répartie. La communication asynchrone est utilisée lorsque la version synchrone est trop lente.

Il importe de considérer les performances dans tout choix. Il y a généralement un compromis à trouver entre les fonctionnalités et les performances. Par exemple, une solution complètement synchrone sur un réseau lent peut diviser les performances par plus de deux, alors qu’une solution asynchrone peut n’avoir qu’un impact minimal sur les performances.

Matrice de fonctionnalités : haute disponibilité, répartition de charge et réplication

Fonctionnalité Bascule par disques partagés (Shared Disk Failover) Réplication par système de fichiers Secours semi-automatique (Hot/Warm Standby) par PITR Réplication maître/esclave basé sur les triggers Middleware de réplication sur instructions Réplication asynchrone multi-maîtres Réplication synchrone multi-maîtres
Exemple d’implémentation NAS DRBD PITR Slony pgpool-II Bucardo
Méthode de communication Disque partagé Blocs disque WAL Lignes de tables SQL Lignes de tables Lignes de tables et verrous de ligne
Ne requiert aucun matériel spécial
Autorise plusieurs serveurs maîtres
Pas de surcharge sur le serveur maître
Pas d’attente entre serveurs
Pas de perte de données en cas de panne du maître
Les esclaves acceptent les requêtes en lecture seule Hot only
Granularité de niveau table
Ne nécessite pas de résolution de conflit
### Quelle solution choisir ?

Il  existe beaucoup de solutions possibles pour faire de la réplication de base de données alors comment choisir ? Il n’existe pas de solution unique pour répondre à cette question, la solution dépend essentiellement du besoin.

Dans notre cas voici les points ont influencé notre choix :

  • Failover / Failback : Failover simple et possibilités de réintégrer le noeud maître.
  • Switchover / Switchback : les opérations de maintenance sur le nœud maître sont facilités.
  • Standalone : si le serveur fils crash le maître n’est pas impacté et peut réintégrer le cluster facilement.
  • Indépendance des versions de PostgreSQL : faciliter les opérations de monté de version.
  • Robuste

Slony

Slony-I™ est un exemple de réplication maître/esclave basé sur des triggers, avec une granularité par table et un support des esclaves multiples. Comme il met à jour le serveur esclave de façon asynchrone (par lots), il existe une possibilité de perte de données pendant un *failover*.
Une configuration de réplication maître/esclave basé sur des triggers envoie toutes les requêtes de modification de données au serveur maître. Ce serveur envoie les modifications de données de façon asynchrone au serveur esclave. L’esclave peut répondre aux requêtes en lecture seule alors que le serveur maître est en cours d’exécution. Le serveur esclave est idéal pour les requêtes vers un entrepôt de données.

Limites :

  • Pas de réplication de la structure d’une base
  • Pas de réplication des Large Objects
  • Par contre, pas de soucis avec les Bytea
  • Pas de réplication du TRUNCATE

Prérequis :

  • Avoir une clé primaire sur chaque table à répliquer (cette clé est nécessaire pour pouvoir identifier chaque ligne de façon certaine).
  • Ne pas modifier fréquemment le schéma de la base de données répliquée.

Paramètres : Pour mettre en place la réplication il faudra connaitre les paramètres suivants :

  • Le nom que l’on souhaite donner à notre cluster de replication
  • adresses IP des serveurs maître et esclave
  • le nom de la base de données que l’on souhaite créé
  • le nom et le mot de passe d’un superuser de la base que l’on veut créer pour effectuer la réplication.

Exemple : Ci dessous les valeurs que l’on utilisera pour notre exemple.

$CLUSTER replication $MASTERHOST 10.55.0.24 $SLAVEHOST 10.55.0.25 $DBNAME slonydb $DBUSER slonyuser $DBPWD password

Installation, Configuration, Démarrage

Installation

Gestion des dépendances : Avant de commencer il faut s’assurer que les dépendances sont installées sur les deux serveurs si ce n’est pas le cas on peut les installer facilement de la manière suivante.

yum install postgresql-server postgresql postgresql-libs perl-DBD-Pg

Installation de Slony : Slony n’est pas supporté par les dépôts par défaut de Redhat5.0, pour l’installer il faudra passer par les dépôts de PostgreSQL. Dans notre exemple nous avons deux serveurs identiques avec une architecture 64bits, une RedHat5.0 et un PostgreSQL8.1.

wget http://yum.pgrpms.org/8.1/redhat/rhel-5.0-x86_64/slony1-1.2.21-1.rhel5.x86_64.rpm rpm -Uvh slony1-1.2.21-1.rhel5.x86_64.rpm yum update yum upgrade

Pour une autre configuration voir ici  http://yum.pgrpms.org/

Configuration et démarage PostgreSQL

Initialisation : Initialiser et démarrer la base sur les deux serveurs pour s’assurer qu’elle a bien été installée.

chkconfig postgresql on service postgresql initdb service postgresql start

Configuration : Modifier la configuration sur les deux serveurs pour rendre la communication entre le serveur maître et esclave possible.

vim /var/lib/pgsql/data/postgresql.conf

Décommenter les lignes suivantes

listen_addresses = '*' port = 5432 vim /var/lib/pgsql/data/pg_hba.conf

Ajouter les lignes suivantes

#host all all $MASTERHOST/32 md5 host all all 10.55.0.24/32 md5 #host all all $SLAVEHOST/32 md5 host all all 10.55.0.25/32 md5

Redémarrer les deux bases pour prendre en compte les modifications apportées.

service postgresql restart

Utilisateur : Création de l’utilisateur slonyuser sur les deux instances. Cette utilisateur sera utilisé pour la réplication et il doit être super user.

#adduser $DBUSER adduser slonyuser #sudo -u postgres createuser -A -D -s $DBUSER -P sudo -u postgres createuser -A -D -s slonyuser -P

Base : Création de la base slonydb sur les deux instances.

#sudo -u slonyuser createdb $DBNAME sudo -u slonyuser createdb slonydb

PLSQL : Slony est basé sur des triggers donc nous aurons besoin d’installer la langue plsql sur le serveur maître.

#sudo -u postgres createlang plpgsql $DBNAME sudo -u postgres createlang plpgsql slonydb

Données maître : Dans cette partie il faut créer le schéma de données sur le serveur maître.
Pour notre exemple nous allons créer une schéma de données simple et le faire évoluer pour illustrer la gestion de sets.

#psql -U $DBUSER -h $MASTERHOST $DBNAME psql -U slonyuser -h 10.55.0.24 slonydb create table t1 (id integer, primary key (id)); create sequence s1 start with 1;

Données esclave : La commande suivante nous permettra de créer un dump de la base maître et de l’exécuter sur la base esclave, ainsi nous obtiendront deux bases identiques.

#pg_dump -s -U $DBUSER -h $MASTERHOST $DBNAME | psql -U $DBUSER -h $SLAVEHOST $DBNAME pg_dump -s -U slonyuser -h 10.55.0.24 slonydb | psql -U slonyuser -h 10.55.0.25 slonydb

Configuration et démarrage de Slony

Configuration : Ici il s’agit de mettre à jour le fichier de configuration pour permettre à Slony de répliquer les données.

vim /etc/slon_tools.conf

Il s’agit ici de définir les informations concernant les bases que l’ont souhaite répliquer.

if ($ENV{"SLONYNODES"}) { require $ENV{"SLONYNODES"}; } else { # nom du cluster $CLUSTER_NAME = 'replication'; # fichier le log $LOGDIR = '/var/log/slony1'; # definition du noeud maitre $MASTERNODE = 1; # information sur le noeud maitre add_node(node = 1, host = '10.55.0.24', #$MASTERHOST dbname = 'slonydb', #$DBNAME port = 5432, user = 'slonyuser', #$DBUSER password = 'password'); #$DBPWD # information sur le noeud esclave add_node(node = 2, host = '10.55.0.25', #$SLAVEHOST dbname = 'slonydb', #$DBNAME port = 5432, user = 'slonyuser', #$DBUSER password = 'password'); #$DBPWD }

Ici nous nous intéresserons à la configuration des sets, tous les objets que l’ont souhaite répliquer doivent être définit dans cette partie. chaque set possède un nom et un id unique, de la même façon Slony associe un id à chaque table et séquence qu’il réplique pour pouvoir gérer facilement par la suite tous ces objets.

$SLONY_SETS = { # un nom unique pour le set "set1" = { # un id unique pour le set "set_id" = 1, "table_id" = 1, "sequence_id" = 1, "pkeyedtables" = [t1,], "sequences" = ['s1',], }, };

Une fois que c’est fini copier le fichier de configuration sur le fils.

#scp /etc/slon_tools.conf root@$MASTERHOST:/etc/slon_tools.conf scp /etc/slon_tools.conf root@10.55.0.25:/etc/slon_tools.conf

Initialisation du cluster

slonik_init_cluster | slonik

Démarrage des démons

slon_start 1 slon_start 2

Ajout des sets

slonik_create_set 1 | slonik slonik_subscribe_set 1 2 | slonik

Maintenance

Gestion des Sets

Ajouter un set : Pour ajouter un set il suffit de le déclarer dans le fichier de configuration slon_tools, de le créer et lui assigner un souscripteur.

Pour illustrer ce cas, nous allons créer une table que l’on va nommer t2 sur la base maître et sur la base esclave. et nous allons la déclarer comme suit dans le fichier de configuration :

vim /etc/slon_tools.conf "temp" = { "set_id" = 2, "table_id" = 2, "pkeyedtables" = [t2,], },

Enfin nous allons créer le set et lui assigner un souscripteur.

slonik_create_set 2 | slonik slonik_subscribe_set 2 2 | slonik

Ajouter un élément d’un set existant : Pour ajouter un élément à un set il faut d’abord créer un set temporaire contenant le ou les élément(s) que l’on souhaite ajouter comme nous l’avons décrit ci dessus, puis fusionner ce set au set que l’on souhaite modifier grâce à la commande slonik_merge_sets. Attention ici le set 2 existent encore il faut le supprimer pour éviter la redondance.

#slonik_merge_sets $set_id $set_to_add_id $origin_node_id | slonik slonik_merge_sets 1 2 1 | slonik

Supprimer un élément d’un set existant : Pour supprimer un élément d’un set existant il faut utiliser suivant la nature de l’élément la commande slonik_drop_table ou bien slonik_drop_sequence.

#slonik_drop_table $table_id $set_id | slonik slonik_drop_table 2 1 | slonik

Supprimer un set : Pour supprimer un set rien de plus simple il suffit d’exécuter la commande slonik_drop_set.

#slonik_drop_set $set_id | slonik slonik_drop_set 2 | slonik

Schéma de réplication

Si les sets subissent beaucoup de modifications, il devient difficile de maintenir un fichier de configuration contenant l’état des différents éléments du cluster. Il est donc intéressant de pouvoir jeter un coup d’œil sur le schéma de Slony stocker sur la base maître.

Le schéma _replication, a été créé par l’instruction Slonik « init cluster ». Son propriétaire est donc l’utilisateur slony, étant donné que toute connexion des démons et outils Slony se fait avec cet utilisateur.

Ci dessous une liste des tables et vues importantes du schéma de réplication.

Table/Vue Commentaires
sl_node liste des nœuds
sl_path liste des chemins entre les différents nœuds
sl_set liste des sets
sl_subscribe liste des abonnements
sl_table liste des tables ajoutées aux différents sets
sl_sequence liste des séquences ajoutées aux différents sets
sl_log1 et 2 liste des modifications pour chaque paire nœud/set
sl_status statut de la réplication
### Switchover[](https://trac.ippon.fr/kb/wiki/Slony#Switchover "Link to this section")

La commande slonik_move_set permet de changer le nœud d’origine d’un set. Dans notre cas lorsque l’on exécute la commande suivante on indique sue le set 1 change d’origine, ce n’est plus le nœud 1 mais c’est le nœud 2 qui devient origine. C’est à dire que le nœud 1 n’acceptera plus que les requêtes en lecture sur tables de ce set et que le nœud 2 acceptera les requêtes en écriture sur les tables de ce set.

#slonik_move_set id_set old_node new_node | slonik slonik_move_set 1 1 2 | slonik

Cette fonctionnalité est intéressante dans le carde d’une maintenance sur le serveur maître.

Failover

Dans le cas d’un crash du serveur maître, la commande slonik_failover permet de signaler au nœud restant que le nœud maître est mort. Dans notre cas la commande permettra au nœud 2 d’autoriser les requêtes de modification de données et de pouvoir ainsi reprendre la relève du serveur maître sans trop de pertes de données.

#slonik_failover old_node new_node | slonik slonik_failover 1 2 | slonik

Ce qu’il faut bien réaliser ici c’est que Slony est une méthode de réplication asynchrone basé sur des démons qui écoutes sur le serveurs maître et de ce fait les dernières transactions commit de moins de 10 secondes avant le crash seront perdues à la suite du failover. Il est donc pas raisonnable de prendre le temps de détecter si le crash vient d’un problème réseau qui sera régler rapidement ou bien d’un problème plus grave suis justifierait cette perte de données.

Reconstruire le cluster

Une fois que l’incident est résolu sur le serveur maître on aura envie de reconstruire le cluster. Dans notre cas après le failover les données du nœud 1 deviennent obsolètes. Il devient donc nécessaire que qu’il rattrape sont retard en devenant esclave du nœud 2 qui deviendra à son tour maître. Cette partie ce fera donc depuis le nœud 2.

Uninstall : Pour cela il faudra avant tout désinstaller le nœud 1 qui se croit encore maître.

#slonik_uninstall_nodes 1 | slonik slonik_uninstall_nodes 1 | slonik

Config : Modifier le fichier de configuration pour indiquer que le maitre est le nœud 2.

vim /etc/slon_tools.conf $MASTERNODE = 2;

Copier le fichier de configuration sur le nœud 1

#scp /etc/slon_tools.conf root@$MASTERHOST:/etc/slon_tools.conf scp /etc/slon_tools.conf root@10.55.0.24:/etc/slon_tools.conf

Initialisation du cluster

slonik_init_cluster | slonik

Démarrage des démons

slon_start 1 slon_start 2

Ajout des sets

slonik_create_set 1 | slonik slonik_subscribe_set 1 1 | slonik

Sources

http://www.postgresql.org

http://slony.info/documentation/1.2/index.html

http://www.pgadmin.org/docs/1.4/slony/index.html

http://www.linuxjournal.com/article/7834?page=0,0

http://www.dalibo.org/hs44_slony_la_replication_des_donnees_par_trigger

http://people.planetpostgresql.org/devrim/index.php?/archives/38-Installing,-configuring,-running-and-administrating-Slony-I-2.0-on-Red-Hat-CentOS-using-RPMs-Part-1.htm

http://people.planetpostgresql.org/devrim/index.php?/archives/42-Installing,-configuring,-running-and-administrating-Slony-I-2.0-on-Red-Hat-CentOS-using-RPMs-Part-II.html