24. Utiliser Slony-I pour les mises à jour PostgreSQL

Un certain nombre de personnes ont trouvé que Slony-I™ était pratique pour effectuer les mises à jours de versions majeures (par exemple celles qui nécessitent d'éxécuter initdb afin de recréer une nouvelle instance) sans subir une coupure de service importante.

La méthode simple que l'on peut imaginer pour effectuer une telle mise à jour consiste à exécuter pg_dump sur l'ancienne version de la base, puis d'envoyer le résultat dans une session psql connectée à la nouvelle version de la base. Malheureusement, le temps nécessaire pour cette approche peut être prohibitif. Pour une base contenant 40 Go de données ainsi que de nombreux index, le processus nécessite les étapes suivantes :

Notez que cette approche a provoqué une coupure de service de 40 heures.

Slony-I™ offre une opportunité de remplacer cette longue coupure de service par une autre de quelques secondes au minimum. L'approche requise consiste à créer un réplicat Slony-I™ utilisant la nouvelle version de PostgreSQL™. Il est possible que cela prenne bien plus de 40 heures pour créer ce réplicat. Néanmoins sa création ne nécessite aucun arrêt de production et, une fois qu'il est créé, il peut être rafraîchi rapidement.

Au moment de basculer vers la nouvelle base de données, la portion de procédure qui requiert un arrêt de production est beaucoup moins longue :

Cette procédure devrait prendre très peu de temps, principalement le temps nécessaire à la reconfiguration de vos applications. Si vous pouvez automatiser toutes ces étapes, le temps hors production devrait être d'une seconde, voire moins. Si la gestion manuelle est nécessaire, cela prendra entre quelques secondes et quelques minutes.

Notez qu'après le déplacement de l'origine, les mises à jour vont vers l'ancienne base. Si vous découvrez qu'à cause d'un problème imprévu ou non testé, votre application rencontre certains problèmes pour se connecter à la nouvelle base, vous pouvez facilement utiliser SLONIK MOVE SET(7) à nouveau pour déplacer de nouveau l'origine vers l'ancienne base.

Si vous considérez qu'il est particulièrement vital de pouvoir revenir à l'ancienne base dans l'état où elle se trouvait avant la bascule, afin de pouvoir revenir complètement en arrière et que vous souhaitez également pouvoir revenir à l'ancienne version (mise à jour depuis la bascule), accomplissez les étapes suivantes :

Si de « petits » problèmes apparaissent, vous pourrez récupérer le nœud qui héberge l'ancienne base qui a reçu les mises à jours de données. Si vous découvrez des problèmes plus importants, vous pouvez abandonner les deux nœuds et revenir à la base qui a été isolée.

Il ne s'agit pas ici de dire qu'il est courant de rencontrer des problèmes qui nécessitent une procédure aussi « paranoïaque ». Toutefois, les personnes soucieuses d'évaluer les risques peuvent être rassurées par de tels choix.

[Note]

Note

Slony-I™ ne supporte pas les versions de PostgreSQL™ antérieures à la 7.3.3 parce qu'il a besoin des espaces de noms (« namespaces ») qui n'étaient pas stables jusque là. Rod Taylor modifia une version de Slony-I™ pour qu'elle fonctionne avec la 7.2 en autorisant les objets Slony-I™ à se placer dans le schéma global. Il trouva cela assez compliqué. De plus, certaines requêtes n'étaient pas assez rapides (l'optimiseur de requêtes de PostgreSQL™ a été considérablement amélioré depuis la version 7.2), cependant cette solution était plus pratique pour lui que les autres systèmes de réplication tels que eRServer™. PostgreSQL™ 7.2 ne sera jamais supportée par une version officielle de Slony-I™.

24.1. Exemple : mise à jour d'une base simple sans réplication existante

Cet exemple montre noms, adresses IP, numéros de port, etc pour décrire en détails ce qui se passe.

24.1.1. L'environnement

Database machine:
        nom = rome 
        ip = 192.168.1.23
        OS: Ubuntu 6.06 LTS
        utilisateur postgres = postgres, groupe postgres
        
Version actuelle de PostgreSQL 
        Version = 8.2.3 
        Port 5432
        Installé sur : /data/pgsql-8.2.3
        Répertoire des données : /data/pgsql-8.2.3/data
        Base de données à déplacer : mydb
        
Nouvelle installation de PostgreSQL
        Version = 8.3.3
        Port 5433
        Installé sur : /data/pgsql-8.3.3
        Répertoire des données : /data/pgsql-8.3.3/data
                        
Version Slony à utiliser = 1.2.14

24.1.2. Installer Slony-I

L'installation de Slony-I™ est couverte assez bien dans les autres parties de la documentation (Section 4, « Installation de Slony-I ») ; nous allons seulement fournir un guide rapide ici.

  wget http://main.slony.info/downloads/1.2/source/slony1-1.2.14.tar.bz2

Déballez l'archive et construisez le paquet en tant que root avec :

tar xjf slony1-1.2.14.tar.bz2
cd slony1-1.2.14
./configure --prefix=/data/pgsql-8.2.3 --with-perltools=/data/pgsql-8.2.3/slony --with-pgconfigdir=/data/pgsql-8.2.3/bin
make clean
make
make install
chown -R postgres:postgres /data/pgsq-8.2.3 
mkdir /var/log/slony
chown -R postgres:postgres /var/log/slony

Puis répétez ceci pour la construction de PostgreSQL 8.3.3. make clean est une étape très importante ; ce n'est pas si important la première fois mais lors de la deuxième construction, il est essentiel de supprimer les anciens binaires, sinon les binaires ne vont pas correspondre à la construction 8.3.3 de PostgreSQL™ 8.3.3 avec comme résultat le non fonctionnement de Slony-I™.

24.1.3. Créer slon_tools.conf

slon_tools.conf est le fichier de configuration. Il contient entre autres :

  1. Tous les nœuds et leurs détails (IP, port, base de données, utilisateur, mot de passe) ;

  2. Toutes les tables à répliquer ;

  3. Toutes les séquences à répliquer ;

  4. L'arrangement des tables et séquences en ensembles.

Faites une copie de /data/pgsql-8.2.3/etc/slon_tools.conf-sample dans slon_tools.conf et ouvrez ce dernier. Les commentaires dans ce fichier sont suffisamment explicatifs. Comme il s'agit d'une réplication en un temps, vous n'aurez généralement pas besoin de créer plusieurs ensembles. Sur une machine de production comprenant 500 tables et 100 séquences, les placer dans un seul ensemble a bien fonctionné.

Quelques modifications à entreprendre :

  1. Dans notre cas, nous avons seulement besoin de deux nœuds, donc supprimez les add_node pour 3 et 4.

  2. L'entrée pkeyedtables doit être mise à jour avec chacune de vos tables qui ont une clé primaire. Si vos tables sont dans différents schémas, vous devez qualifier le nom de la table avec celui du schéma (nomschéma.nomtable).

  3. L'entrée keyedtables doit être mise à jour avec toute table correspondant au commentaire (si la conception du schéma est bonne, il ne devrait pas y en avoir).

  4. serialtables (si vous en avez, mais il est préférable de les éviter).

  5. sequences doit être mise à jour avec la liste de vos séquences.

  6. Supprimez complètement l'entrée set2 (car nous allons seulement utilisé set1).

Voici à quoi cela ressemble une fois tous les commentaires supprimés :

$CLUSTER_NAME = 'replication';
$LOGDIR = '/var/log/slony';
$MASTERNODE = 1;

    add_node(node     => 1,
             host     => 'rome',
             dbname   => 'mydb',
             port     => 5432,
             user     => 'postgres',
         password => '');

    add_node(node     => 2,
             host     => 'rome',
             dbname   => 'mydb',
             port     => 5433,
             user     => 'postgres',
         password => '');

$SLONY_SETS = {
    "set1" => {
        "set_id" => 1,
        "table_id"    => 1,
        "sequence_id" => 1,
        "pkeyedtables" => [
                           'mytable1',
                           'mytable2',
                           'otherschema.mytable3',
                           'otherschema.mytable4',
                           'otherschema.mytable5',
                           'mytable6',
                           'mytable7',
                           'mytable8',
                           ],

                "sequences" => [
                           'mytable1_sequence1',
                           'mytable1_sequence2',
                           'otherschema.mytable3_sequence1',
                           'mytable6_sequence1',
                           'mytable7_sequence1',
                           'mytable7_sequence2',
                        ],
    },

};

1;
  

Comme vous le voyez, cette base de données est très petite avec seulement huit tables et six séquences. Maintenant, copiez votre fichier slon_tools.conf dans /data/pgsql-8.2.3/etc/ et /data/pgsql-8.3.3/etc/.

24.1.4. Préparer la nouvelle instance PostgreSQL

Vous avez maintenant une toute nouvelle seconde instance de PostgreSQL™ fonctionnant sur le port 5433 de la même machine. C'est le moment de préparer la réception des données à répliquer par Slony-I™.

  1. Slony ne réplique pas les rôles, donc il faut tout d'abord créer tous les utilisateurs sur la nouvelle instance pour qu'elle soit identique en terme de rôles/groupes.

  2. Créez votre base de données dans le même encodage que la base de données origine, dans mon cas il s'agit de l'UTF8 /data/pgsql-8.3.3/bin/createdb -E UNICODE -p5433 mydb

  3. Slony-I™ réplique les données, pas les schémas. Donc faites une sauvegarde de votre schéma avec la commande /data/pgsql-8.2.3/bin/pg_dump -s mydb > /tmp/mydb.schema puis importez-le dans la nouvelle instance avec cat /tmp/mydb.schema | /data/pgsql-8.3.3/bin/psql -p5433 mydb

La nouvelle base de données est enfin prête à recevoir les données de la réplication.

24.1.5. Lancer la réplication Slony-I

C'est le moment où nous commençons à modifier la base de données de production en y ajoutant un nouveau schéma contenant toutes les informations de réplication de Slony-I™.

La première chose à faire est d'initialiser le schéma de Slony-I™. Faites-le en tant qu'utilisateur postgres, comme dans l'exemple qui suit.

[Note]

Note

Toutes les commandes commençant avec slonik ne font rien elles-même. Elles génèrent des commandes qui peuvent être interprétées par l'outil slonik. Donc exécuter des scripts commençant par slonik_ ne fera rien à votre base de données. De plus, par défaut, les scripts slonik_ recherchent votre fichier slon_tools.conf dans le sous-répertoire etc du répertoire PostgreSQL, dans mon cas /data/pgsql-8.x.x/etc.

/data/pgsql-8.2.3/slony/slonik_init_cluster > /tmp/init.txt

Ouvrez /tmp/init.txt et vérifiez qu'il contient un texte ressemblant à celui disponible ci-dessous :

# INIT CLUSTER
cluster name = replication;
 node 1 admin conninfo='host=rome dbname=mydb user=postgres port=5432';
 node 2 admin conninfo='host=rome dbname=mydb user=postgres port=5433';
  init cluster (id = 1, comment = 'Node 1 - mydb@rome');

# STORE NODE
  store node (id = 2, event node = 1, comment = 'Node 2 - mydb@rome');
  echo 'Set up replication nodes';

# STORE PATH
  echo 'Next: configure paths for each node/origin';
  store path (server = 1, client = 2, conninfo = 'host=rome dbname=mydb user=postgres port=5432');
  store path (server = 2, client = 1, conninfo = 'host=rome dbname=mydb user=postgres port=5433');
  echo 'Replication nodes prepared';
  echo 'Please start a slon replication daemon for each node';

La première section indique les informations du nœud et l'initialisation du cluster. Puis il y a l'ajout du deuxième nœud au cluster. Enfin, les chemins de communication sont stockés pour les deux nœuds dans le schéma de slony.

C'est le bon moment pour exécuter la commande : cat /tmp/init.txt | /data/pgsql-8.2.3/bin/slonik

L'exécution sera rapide et indiquera par un affichage le succès.

En cas d'échec, les raisons les plus probables sont un problème de droits sur la base de données, une mauvaise configuration de pg_hba.conf ou une erreur de saisie dans slon_tools.conf. Cherchez le problème et résolvez-le. Si les schémas slony ont été créés mais que le script échoue toujours, vous pouvez exécuter le script slonik_uninstall_nodes pour tout nettoyer. Dans le pire des cas, vous pouvez vous connecter à chaque base de données et exécuter drop schema _replication cascade; pour bien nettoyer.

24.1.6. Le démon slon

Comme l'indique le résultat de la dernière commande, nous devons maintenant lancer le démon de réplication slon pour chaque nœud. Le démon slon est le moteur de la réplication. Tous les transferts et tout le reste du travail sont réalisés par le démon slon. Il est nécessaire d'en avoir un pour chaque nœud. Donc, dans notre cas, nous en avons besoin d'un pour l'installation 8.2.3 et un autre pour la 8.3.3.

Pour lancer celui de la 8.2.3, faites ceci : /data/pgsql-8.2.3/slony/slon_start 1 --nowatchdog Ceci va démarrer le démon du nœud 1. L'option --nowatchdog est intéressante car nous faisons une toute petite réplication et que nous n'avons donc pas besoin de chiens de garde ayant un œil sur l'exécution du processus slon.

S'il démarre bien, jetez un œil dans les traces du répertoire /var/log/slony/slony1/node1/. Elles doivent indiquer que le processus s'est bien lancé.

Nous avons besoin d'en lancer un aussi pour la 8.3.3. /data/pgsql-8.3.3/slony/slon_start 2 --nowatchdog

S'il démarre bien, jetez un œil dans les traces du répertoire /var/log/slony/slony1/node2/. Elles doivent indiquer que le processus s'est bien lancé.

24.1.7. Ajouter l'ensemble de réplication

Maintenant, nous avons besoin d'indiquer à slon les tables et séquences à répliquer. Nous devons donc créer l'ensemble de réplication.

Exécutez la commande suivante : /data/pgsql-8.2.3/slony/slonik_create_set set1 > /tmp/createset.txt

/tmp/createset.txt peut devenir vraiment gros, cela dépend du nombre de tables ; de toute façon, jetez-y un œil pour vérifier qu'il a bien défini toutes les tables et séquences à répliquer.

Si vous êtes satisfait du résultat, envoyez le fichier à slonik pour qu'il soit exécuté : cat /tmp/createset.txt | /data/pgsql-8.2.3/bin/slonik Vous verrez des traces indiquant chaque table à répliquer.

Et voilà, vous avez défini l'ensemble de tables et séquences à répliquer.

24.1.8. L'abonnement

L'étape finale est d'obtenir toutes les données sur la nouvelle base de données. Cela se fait simplement en utilisant le script d'abonnement. data/pgsql-8.2.3/slony/slonik_subscribe_set 1 2 > /tmp/subscribe.txt Le premier argument est l'identifiant de l'ensemble, le second est celui du nœud à abonner.

Ce script généré ressemble à ceci :

 cluster name = replication;
 node 1 admin conninfo='host=rome dbname=mydb user=postgres port=5432';
 node 2 admin conninfo='host=rome dbname=mydb user=postgres port=5433';
  try {
    subscribe set (id = 1, provider = 1, receiver = 2, forward = yes);
  }
  on error {
    exit 1;
  }
  echo 'Subscribed nodes to set 1';
  

Envoyez-le à slonik : cat /tmp/subscribe.txt | /data/pgsql-8.2.3/bin/slonik

La réplication va maintenant commencer. Elle va copier toutes les données des tables/séquences appartenant à l'ensemble de réplication. Cela peut prendre du temps, suivant la taille de la base de données et la puissance de la machine.

Une façon de visualiser la progression est de regarder le contenu des traces avec la commande : tail -f /var/log/slony/slony1/node2/log | grep -i copy Les traces de slony sont verbeuses, mais cela vous permettra de suivre l'avancée de la réplication initiale. À un moment, vous verrez le message « copy completed sucessfully in xxx seconds ». Cela vous dira que la réplication initiale est terminée !

Une fois que ceci est fait, il va commencer à rattraper l'activité survenue depuis le début de la réplication initiale. Vous pouvez facilement voir la progression de ce processus dans la base de données. Connectez-vous à la base de données maître. Il existe une vue appelée sl_status dans le schéma de la réplication. Le champ le plus intéressant est st_lag_num_event. Cela déclare le nombre d'événements slony en retard. 0 est le but à atteindre. Évidemment, cela dépend de l'activité de votre base de données. Le champ suivant est st_lag_time, une estimation du temps restant. À considérer avec prudence, st_lag_num_event étant une mesure bien plus précise.

Vous avez maintenant une base de données entièrement répliquée.

24.1.9. La bascule

Notre base de données est entièrement répliquée. Il existe différentes options pour faire la bascule.

  1. Tout d'abord, modifiez le fichier postgresql.conf pour que la version 8.3.3 utilise le port 5432, de façon à ce qu'il soit prêt dès le redémarrage.

  2. À partir de ce moment, vous êtes hors production. Arrêtez le serveur 8.2.3.

  3. Redémarrez le serveur 8.3.3. Cela ne devrait pas poser de problèmes.

  4. Supprimez les objets slony du serveur 8.3.3, puis exécutez la commande : drop schema _replication cascade;

Vous êtes maintenant en 8.3.3. La mise à jour est terminée avec, on l'espère, un temps minimal passé hors production. Cette procédure est la façon le plus simple de le faire.