2. Répliquer votre première base de données

Dans cet exemple, nous allons répliquer une base de données pgbench neuve. Les mécanismes de réplications d'une base existante sont abordés ici, cependant nous vous recommandons d'apprendre comment utiliser les fonctions Slony-I™ en utilisant une base fraîchement créée, placée sur un serveur qui n'est pas en production.

Notez que pgbench est un outil de « tests » (« benchmark ») qui se trouve parmi les outils contrib de PostgreSQL™ Si vous compilez PostgreSQL™ depuis les sources, vous devez vous rendre dans le répertoire contrib/pgbench et exécuter la commande make install pour le compiler et l'installer ; vous pouvez par ailleurs le trouver inclus dans les paquets binaires de PostgreSQL™.

Le moteur de réplication de Slony-I™ est basé sur les triggers, ce qui permet de répliquer des bases de données (ou des parties de celles-ci) hébergées par le même postmaster.

Cet exemple montre comment répliquer la base pgbench hébergée sur localhost (maître) vers la base pgbench esclave hébergée elle-aussi sur localhost (esclave). Nous nous basons sur deux suppositions à propos de votre configuration de PostgreSQL™ :

L'utilisateur REPLICATIONUSER doit être un super-utilisateur PostgreSQL™. C'est en général postgres ou pgsql. Cependant, au sein d'environnements complexes, il est parfois judicieux de définir un utilisateur slony pour distinguer les différents rôles.

Vous devez également définir les variables shell suivantes :

Voici deux manières de paramétrer ces variables avec un shell standard :

[Avertissement]

Avertissement

Si vous changez vos variables afin d'utiliser différents hôtes pour MASTERHOST et SLAVEHOST, soyez certain de ne pas utiliser localhost pour aucun des deux. Ceci provoquerait une erreur similaire à celle-ci :

ERROR remoteListenThread_1: db_getLocalNodeId() returned 2 - wrong database?

2.1. Créer l'utilisateur pgbench

createuser -A -D $PGBENCHUSER

2.2. Préparer les bases

createdb -O $PGBENCHUSER -h $MASTERHOST $MASTERDBNAME
createdb -O $PGBENCHUSER -h $SLAVEHOST $SLAVEDBNAME
pgbench -i -s 1 -U $PGBENCHUSER -h $MASTERHOST $MASTERDBNAME

Une des tables créées par pgbench, history, n'a pas de clé primaire. Dans les versions antérieures de Slony-I™, une commande nommée SLONIK TABLE ADD KEY(7) pouvait être utilisées pour en introduire une. Ceci provoquait de nombreux problèmes si bien que cette fonctionnalité fut supprimée dans la version 2 de Slony-I™. Il est désormais nécessaire d'avoir une ensemble éligible en tant que clé primaire.

Les requêtes SQL suivantes établissent une clé primaire cohérente pour cette table :

psql -U $PGBENCHUSER -h $HOST1 -d $MASTERDBNAME -c "begin; alter table
history add column id serial; update history set id =
nextval('history_id_seq'); alter table history add primary key(id);
commit"

Puisque Slony-I™ dépend de la présence du langage procédural pl/pgSQL, nous devons l'installer maintenant. Il est possible que vous ayez installé pl/pgSQL dans la base template1, auquel cas vous pouvez sauter cette étape car le langage est installé par défaut dans la base $MASTERDBNAME.

createlang -h $MASTERHOST plpgsql $MASTERDBNAME

Slony-I™ ne copie pas automatiquement les définitions de tables du maître lorsqu'un esclave s'y connecte, ainsi nous devons importer ces données. Nous réalisons cette opération avec pg_dump.

pg_dump -s -U $REPLICATIONUSER -h $MASTERHOST $MASTERDBNAME
  | psql -U $REPLICATIONUSER -h $SLAVEHOST $SLAVEDBNAME

Pour illustrer comment Slony-I™ permet une réplication à la volée, nous lançons l'application pgbench. Si vous exécutez pgbench en tâche de premier plan dans une fenêtre de terminal séparée, vous pouvez l'arrêter et le relancer à tout moment avec des paramètres différents. Vous devrez exporter les variables d'environnement pour qu'elles soient également disponibles dans cette session.

La commande habituelle pour exécuter pgbench est :

pgbench -s 1 -c 5 -t 1000 -U $PGBENCHUSER -h $MASTERHOST $MASTERDBNAME

Ceci lancera pgbench avec cinq clients concurrents, exécutant chacun 1000 transactions sur la base pgbench hébergées sur localhost, en utilisant l'utilisateur pgbench.

2.3. Configurer la base de donnée pour la réplication

La création des tables de configuration, des procédures stockées, des triggers et la configuration sont prises en charges par l'outil slonik(1). Il s'agit d'un script d'aide spécialisé qui appelle principalement des procédures stockées sur les nœuds maître et esclaves.

L'exemple qui suit utilise slonik(1) directement (ou l'embarque directement dans les scripts). Ce n'est pas forcément la façon la plus plaisante pour débuter : il existe des outils pour construire les scripts de slonik(1) dans le répertoire tools :

  • Section 21.1, « Les scripts altperl » - un ensemble de scripts Perl qui construisent des scripts slonik(1) basés sur un seul fichier slon_tools.conf.

  • Section 21.2, « mkslonconf.sh » - un script shell (c'est-à-dire qu'il fonctionne avec Bash) qui, en se basant soit sur sa configuration interne soit sur les variables d'environnement, génère un ensemble de scripts slonik(1) pour configurer un cluster complet.

2.3.1. Utiliser directement les commandes slonik

L'approche traditionnelle pour administrer slony consiste à utiliser directement les commandes slonik. En voici un exemple.

Le script de création de la configuration initiale pour une simple configuration maître-esclave de la base pgbench est le suivant :

#!/bin/sh

slonik <<_EOF_
        #--
        # définition de l'espace de nom du système de réplication
        # dans notre exemple, il s'agit de exemple_slony
        #--
        cluster name = $CLUSTERNAME;

        #--
        # les paramètres "admin conninfo" sont utilisé par slonik pour se
        # connecter aux noeuds. Une ligne par noeud. La syntaxe est celle de
        # PQconnectdb de l'API C
        # --
        node 1 admin conninfo = 'dbname=$MASTERDBNAME host=$MASTERHOST user=$REPLICATIONUSER';
        node 2 admin conninfo = 'dbname=$SLAVEDBNAME host=$SLAVEHOST user=$REPLICATIONUSER';

        #--
        # initialisation du premier noeud. Son identifiant DOIT être 1. Cela
        # provoque la création du schéma _$CLUSTERNAME contenant tous les objets
        # spécifiques du système de réplication
        #--
        init cluster ( id=1, comment = 'Master Node');
 
        #--
        # Slony-I regroupe les tables dans des ensembles.
        # La plus petite unité qu'un noeud peut répliquer est un ensemble.
        # Les commandes suivantes crées un ensemble contenant 4 tables pgbench.
        # Le maître (ou origine) de l'ensemble est le noeud 1.
        #--
        create set (id=1, origin=1, comment='All pgbench tables');
        set add table (set id=1, origin=1, id=1, fully qualified name = 'public.accounts', comment='accounts table');
        set add table (set id=1, origin=1, id=2, fully qualified name = 'public.branches', comment='branches table');
        set add table (set id=1, origin=1, id=3, fully qualified name = 'public.tellers', comment='tellers table');
        set add table (set id=1, origin=1, id=4, fully qualified name = 'public.history', comment='history table');

        #--
        # Création du second noeud (l'esclave) 
        # décrit comment les 2 noeuds vont se connecter l'un à l'autre
        # et quelle manière ils vont écouter les événements..
        #--
        store node (id=2, comment = 'Slave node', event node=1);
        store path (server = 1, client = 2, conninfo='dbname=$MASTERDBNAME host=$MASTERHOST user=$REPLICATIONUSER');
        store path (server = 2, client = 1, conninfo='dbname=$SLAVEDBNAME host=$SLAVEHOST user=$REPLICATIONUSER');
_EOF_

L'application pgbench est-elle toujours exécutée ? Si ce n'est pas le cas, redémarrez-la.

À ce moment, nous avons deux bases de données qui sont complètement préparées. L'une d'elle est la base maître, celle que l'application pgbench utilise pour lire et modifier des lignes. Le temps est donc venu de lancer les démons de réplication.

Sur $MASTERHOST, la commande pour démarrer le moteur de réplication est :

slon $CLUSTERNAME "dbname=$MASTERDBNAME user=$REPLICATIONUSER host=$MASTERHOST"

De la même façon, nous démarrons le système de réplication sur le nœud 2 (l'esclave) :

slon $CLUSTERNAME "dbname=$SLAVEDBNAME user=$REPLICATIONUSER host=$SLAVEHOST"

Même si nous avons désormais le démon slon(1) exécuté à la fois sur le maître et l'esclave, et qu'ils sont tous les deux en train de cracher des diagnostiques et d'autres messages, les données ne sont toujours pas répliquées. L'activité que vous constatez est la synchronisation de la configuration du cluster entre les deux processus slon(1).

Pour démarrer la réplication des quatre tables pgbench (l'ensemble 1) depuis le maître (le nœud 1) vers l'esclave (le nœud 2), lancez le script suivant :

#!/bin/sh
slonik <<_EOF_
         # ----
         # Définition de l'espace de nom du cluster
         # ----
         cluster name = $CLUSTERNAME;

         # ----
         # Les paramètres conninfo sont utilisés par le programme slonik
         # pour se connecter aux noeuds. Ce sont donc les arguments
         # PQconnectdb pour se connecter depuis la station de travail
         # d'administration (où les scripts slonik sont exécutés).
         # ----
         node 1 admin conninfo = 'dbname=$MASTERDBNAME host=$MASTERHOST user=$REPLICATIONUSER';
         node 2 admin conninfo = 'dbname=$SLAVEDBNAME host=$SLAVEHOST user=$REPLICATIONUSER';

         # ----
         # Le noeud 2 s'abonne à l'ensemble 1
         # ----
         subscribe set ( id = 1, provider = 1, receiver = 2, forward = no);
_EOF_

Désormais, le démon de réplication sur$SLAVEHOST se déclenchera à tout moment pour copier les changements d'états sur les quatre tables répliquées. Pendant ce temps, l'application pgbench va continuer à modifier la base de données. Lorsque le processus de copie est terminé, le démon de réplication sur le nœud $SLAVEHOST commencera à se synchroniser en appliquant les journaux de réplication qui auront été accumulés. Cela se fera par petit à petit, en commençant par tranches de 10 secondes de travail applicatifs. Selon les performances des deux systèmes impliqués, la taille des deux bases de données, la charge de transaction et la qualité de l'optimisation et de la maintenance effectuées sur les deux bases de données, ce processus de synchronisation peut durer quelques minutes, quelques heures ou quelques siècles.

Si vous rencontrez des problèmes pour faire fonctionner ceci, vérifiez les journaux applicatifs des processus slon(1) car il y a de fortes chances que des messages d'erreur intéressants décrivent la nature du problème. L'outil Section 5.1, « test_slony_state » peut aussi être utile pour diagnostiquer les problèmes avec des clusters de réplication pratiquement fonctionnels.

Vous avez maintenant configuré avec succès votre premier système de réplication maître-esclave basique, et les deux bases de données devraient, une fois que l'esclave sera synchronisé, contenir des données identiques. Ça, c'est la théorie, tout du moins. En pratique, il est bon de vérifier que les ensembles de données sont bien identiques.

Le script ci-dessous crée des sauvegardes ordonnées des deux bases et les compare. Assurez-vous que le test pgbench est terminé, qu'il n'y pas d'autres mises à jour en cours sur le nœud origine, et que les sessions slon se sont synchronisées.

#!/bin/sh
echo -n "**** comparing sample1 ... "
psql -U $REPLICATIONUSER -h $MASTERHOST $MASTERDBNAME >dump.tmp.1.$$ <<_EOF_
         select 'accounts:'::text, aid, bid, abalance, filler
                  from accounts order by aid;
         select 'branches:'::text, bid, bbalance, filler
                  from branches order by bid;
         select 'tellers:'::text, tid, bid, tbalance, filler
                  from tellers order by tid;
         select 'history:'::text, tid, bid, aid, delta, mtime, filler,
                  "_Slony-I_${CLUSTERNAME}_rowID"
                  from history order by "_Slony-I_${CLUSTERNAME}_rowID";
_EOF_
psql -U $REPLICATIONUSER -h $SLAVEHOST $SLAVEDBNAME >dump.tmp.2.$$ <<_EOF_
         select 'accounts:'::text, aid, bid, abalance, filler
                  from accounts order by aid;
         select 'branches:'::text, bid, bbalance, filler
                  from branches order by bid;
         select 'tellers:'::text, tid, bid, tbalance, filler
                  from tellers order by tid;
         select 'history:'::text, tid, bid, aid, delta, mtime, filler,
                  "_Slony-I_${CLUSTERNAME}_rowID"
                  from history order by "_Slony-I_${CLUSTERNAME}_rowID";
_EOF_

if diff dump.tmp.1.$$ dump.tmp.2.$$ >$CLUSTERNAME.diff ; then
         echo "success - databases are equal."
         rm dump.tmp.?.$$
         rm $CLUSTERNAME.diff
else
         echo "FAILED - see $CLUSTERNAME.diff for database differences"
fi

Notez qu'il existe une documentation un peu plus sophistiquée concernant ce processus dans l'arborescence du code source de Slony-I™ au sein d'un fichier nommé slony-I-basic-mstr-slv.txt.

Si ce script renvoie FAILED, merci de contacter les développeurs sur http://slony.info/. Préparez-vous aussi à fournir des informations de diagnostique, comme les journaux applicatifs créés par les processus slon(1) et les résultats de la commande Section 5.1, « test_slony_state ».

2.3.2. Utiliser les scripts altperl

L'utilisation des scripts Section 21.1, « Les scripts altperl » est une autre façon de débuter ; cela vous évite d'avoir à écrire les scripts slonik, au moins pour certaines des façons simples de configurer Slony-I™. Le script slonik_build_env génère une sortie fournissant les détails dont vous avez besoin pour créer le fichier slon_tools.conf, dont la présence est nécessaire pour les scripts. Un exemple de fichier slon_tools.conf est fourni dans la distribution pour vous aider à commencer. Les scripts altperl font tous référence à ce fichier de configuration central. Une fois que slon_tools.conf est créé, vous pouvez continuer ainsi :

# Initialisation du cluster :
$ slonik_init_cluster  | slonik 

# Lancement de slon  (ici 1 et 2 sont les numéros de noeuds)
$ slon_start 1    
$ slon_start 2

# Créer les ensembles (ici 1 est le numéro de l'ensemble)
$ slonik_create_set 1 | slonik             

# abonner le second noeud à l'ensemble (1= identifiant du set, 2= identifiant du noeud)
$ slonik_subscribe_set 1 2 | slonik

Vous avez maintenant répliqué votre première base de données. Vous pouvez ignorer la section suivante de la documentation si vous le souhaitez. Elle documente une approche plus complexe.