Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
705 lines (618 sloc) 23.4 KB
<?xml version="1.0" encoding="UTF-8"?>
<!-- Dernière modification
le $Date$
par $Author$
révision $Revision$ -->
<sect1 id="logshipping">
<title>Log Shipping</title>
<indexterm><primary>log shipping</primary></indexterm>
<para>
Une des nouvelles fonctionnalités de la version 1.1, qui ne fut réellement
stable qu'à partir de la version 1.2.11, est la possibilité de regrouper
les mises à jour dans des fichiers de journalisation qui sont stockés dans
un répertoire d'attente.
</para>
<para>
Ces fichiers de journalisation peuvent alors être transférés selon la
méthode de votre choix vers le <quote>serveur esclave</quote>, que ce soit
via FTP, rsync ou même avec une <quote>clé USB</quote> d'1&nbsp;Go
transportée par avion.
</para>
<para>
Il y a plein de choses intéressantes à faire avec un tel flux de données,
en particulier&nbsp;:
<itemizedlist>
<listitem>
<para>
Répliquer des n&oelig;uds qui <emphasis>ne peuvent pas</emphasis> être
securisés&nbsp;;
</para>
</listitem>
<listitem>
<para>
Répliquer dans des lieux où il n'est pas possible d'établir des
communications bidirectionnelles&nbsp;;
</para>
</listitem>
<listitem>
<para>
Utiliser une nouvelle forme de <acronym>PITR</acronym> (Point In Time
Recovery) qui filtre les transactions composées uniquement de lectures
et celles qui mettent à jour des tables qui ne sont pas
intéressantes&nbsp;;
</para>
</listitem>
<listitem>
<para>
En cas de désastre, vous pouvez regarder à l'intérieur des fichiers de
journalisation pour voir le détail des requêtes&nbsp;;
</para>
<para>
Cela rend le log shipping potentiellement utile même si vous n'avez pas
réellement l'intention de créer un n&oelig;ud répliqué&nbsp;;
</para>
</listitem>
<listitem>
<para>
C'est une méthode très subtile pour charger des données en vue de
tests&nbsp;;
</para>
</listitem>
<listitem>
<para>
Nous avons un système <quote>escrow</quote> qui serait incroyablement
moins cher avec du log shipping&nbsp;;
</para>
</listitem>
<listitem>
<para>
Vous pouvez appliquer des triggers sur un <quote>n&oelig;ud
déconnecté</quote> pour effectuer des traitements supplémentaires sur
les données.
</para>
<para>
Par exemple, vous pouvez prendre une base relativement
<quote>statique</quote> et la transformer en une table
<quote>temporelle</quote>, en utilisant des triggers qui implémentent
les techniques décrites dans <citation>Developing Time-Oriented
Database Applications in SQL</citation> de <ulink
url="http://www.cs.arizona.edu/people/rts/">Richard T. Snodgrass</ulink>.
</para>
</listitem>
</itemizedlist>
</para>
<qandaset>
<qandaentry>
<question>
<para>
Où sont générés les <quote>fichiers de journalisation</quote> d'un
ensemble de réplication donné&nbsp;?
</para>
</question>
<answer>
<para>
Chaque n&oelig;ud abonné <link linkend="slon">slon</link> peut les
générer en ajoutant l'option <option>-a</option>.
</para>
<note>
<para>
Notez que cela implique que, pour utiliser le log shipping, vous
devez avoir au moins un n&oelig;ud abonné.
</para>
</note>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Que se passe-t-il lors d'un <xref linkend="stmtfailover"/>/<xref
linkend="stmtmoveset"/>&nbsp;?
</para>
</question>
<answer>
<para>
Rien de spécial. Tant que le n&oelig;ud d'archivage reste un abonné,
il continue à produire des fichiers de journalisation.
</para>
</answer>
<answer>
<warning>
<para>
Si le n&oelig;ud d'archivage devient l'origine, il continuera à
produire des fichiers de journalisation.
</para>
</warning>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Que se passe-t-il lorsqu'il n'y a plus assez d'espace pour les fichiers
de journalisation&nbsp;?
</para>
</question>
<answer>
<para>
Le n&oelig;ud n'accepte plus les événements <command>SYNC</command>
jusqu'à ce que le problème soit réglé. La base de donnée qui est
dupliquée tombe également en panne.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Comment réaliser un abonnement&nbsp;?
</para>
</question>
<answer>
<para>
Le script dans <filename>tools</filename> nommé
<application>slony1_dump.sh</application> est un script shell qui
exporte l'état <quote>actuel</quote> du n&oelig;ud abonné.
</para>
<para>
Vous devez lancer le démon <application><link
linkend="slon">slon</link></application> pour le n&oelig;ud abonné
avec le log shipping activé. À tout moment, vous pouvez lancer la
commande <application>slony1_dump.sh</application>, qui va récupérer
l'état de l'abonné sous la forme d'événements <command>SYNC</command>.
Une fois que l'export est complet, tous les logs <command>SYNC</command>
produits à partir du moment où l'export a <emphasis>démarré</emphasis>
seront ajoutés à l'export afin d'obtenir un <quote>n&oelig;ud abonné
au log shipping</quote>.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
Quelles sont les limitations du log shipping&nbsp;?
</para>
</question>
<answer>
<para>
Dans la version initiale, il y avait beaucoup de limitations.
Heureusement, au fur et à mesure des nouvelles versions, certaines de
ces limitations ont été corrigées ou supprimées.
</para>
</answer>
<answer>
<para>
La fonctionnalité du log shipping revient à <quote>sniffer</quote>
les données appliquées sur un n&oelig;ud abonné. En conséquence,
vous devez avoir au moins un n&oelig;ud <quote>standard</quote>&nbsp;;
vous ne pouvez pas avoir un cluster composé seulement d'une origine et
d'un ensemble de <quote>n&oelig;uds de log shipping</quote>.
</para>
</answer>
<answer>
<para>
Le <quote>n&oelig;ud de log shipping</quote> traque la totalité du
trafic allant vers un abonné. Vous pouvez séparer les choses lorsqu'il
y a plusieurs ensembles de réplication.
</para>
</answer>
<answer>
<para>
Actuellement, le <quote>n&oelig;ud de log shipping</quote> traque
uniquement les événements <command>SYNC</command>. Cela devrait être
suffisant pour gérer <emphasis>certains</emphasis> changements de la
configuration du cluster, mais pas tous.
</para>
<para>
Une bonne partie des types événements <emphasis>sont</emphasis> gérés
afin que le log shipping puissent les traiter&nbsp;:
<itemizedlist>
<listitem>
<para>
Bien évidemment, les événements <command>SYNC </command> sont
gérés.
</para>
</listitem>
<listitem>
<para>
Les <command>DDL_SCRIPT</command> sont gérés.
</para>
</listitem>
<listitem>
<para>
<command>UNSUBSCRIBE_SET</command>
</para>
<para>
Cet événement, tout comme <command>SUBSCRIBE_SET</command>, n'est
pas géré par le n&oelig;ud de log shipping. Mais cette commande,
par définition, implique que les événements <command>SYNC</command>
ne contiennent plus de mises à jour pour l'ensemble de réplication.
</para>
<para>
De la même façon, <command>SET_DROP_TABLE</command>,
<command>SET_DROP_SEQUENCE</command>,
<command>SET_MOVE_TABLE</command>,
<command>SET_MOVE_SEQUENCE</command>, <command>DROP_SET</command>,
<command>MERGE_SET</command> seront gérés de manière
<quote>appropriée</quote>.
</para>
</listitem>
<listitem>
<para>
<command>SUBSCRIBE_SET</command>
</para>
<para>
Malheureusement, des choses <quote>étranges</quote> surviennent
lorsqu'on gère cette commande... Quand un
<command>SUBSCRIBE_SET</command> se produit, cela déclenche un
évènement nommé <command>ENABLE_SUBSCRIPTION</command> qui est
levé et traité uniquement sur le n&oelig;ud abonné.
</para>
<para>
<command>SUBSCRIBE_SET</command> est vraiment un événement
très simple. Il se contente de <emphasis>déclarer</emphasis>
qu'un n&oelig;ud s'abonne à un ensemble donné via un fournisseur
donné. <emphasis>Il ne copie pas les données&nbsp;!</emphasis>
</para>
<para>
Le c&oelig;ur du travail de souscription est réalisé par
<command>ENABLE_SUBSCRIPTION</command>, qui est un événement
déclenché sur le n&oelig;ud local, et non pas dans la même
séquence que les autres événements en provenance des autres
n&oelig;uds (notament le fournisseur de données).
</para>
<para>
Avec la modifications du traitement des fichiers de journalisation
intervenus dans la version 1.2.11, ceci ne présente plus de
problèmes pour l'utilisateur.
</para>
</listitem>
<listitem>
<para>
Les différents événements impliqués dans la configuration d'un
n&oelig;ud sont inutiles dans le cadre du log shipping&nbsp;:
<command>STORE_NODE</command>,
<command>ENABLE_NODE</command>,
<command>DROP_NODE</command>,
<command>STORE_PATH</command>,
<command>DROP_PATH</command>,
<command>STORE_LISTEN</command>,
<command>DROP_LISTEN</command>.
</para>
</listitem>
<listitem>
<para>
Les événements impliqués dans la configuration des ensembles de
réplication sont également inutiles&nbsp;:
<command>STORE_SET</command>,
<command>SET_ADD_TABLE</command>,
<command>SET_ADD_SEQUENCE</command>,
<command>STORE_TRIGGER</command>,
<command>DROP_TRIGGER</command>,
<command>TABLE_ADD_KEY</command>
</para>
</listitem>
</itemizedlist>
</para>
</answer>
<answer>
<para>
Il serait pratique de transformer un n&oelig;ud de <quote>log
shipping</quote> en un n&oelig;ud &slony1; complètement fonctionnel sur
lequel on pourrait basculer. Cela serait utile (par exemple) pour un
cluster de 6 n&oelig;uds&nbsp;; cela permettrait de commencer par
créer un n&oelig;ud abonné puis d'utiliser le log shipping pour
construire les 4 autres n&oelig;uds en parallèle.
</para>
<para>
Cette utilisation n'est pas possible, mais on peut ajouter la
configuration &slony1; dans un n&oelig;ud, et le promouvoir en tant
que nouveau n&oelig;ud. Encore une fois, c'est une simple question de
programmation (mais ça n'est pas forcément si simple)...
</para>
</answer>
</qandaentry>
</qandaset>
<sect2>
<title>Conseils d'utilisation</title>
<note>
<para>
Voici quelques notes plus ou moins structurées sur l'utilisation idéale
du log shipping...
</para>
</note>
<itemizedlist>
<listitem>
<para>
Vous ne <emphasis>devez</emphasis> pas appliquer aveuglément les fichiers
<command>SYNC</command> car on ne peut pas prendre un fichier
<command>SYNC</command> au hasard. Si ce n'est pas un fichier approprié,
alors la commande <function>setsyncTracking_offline()</function> échouera
et votre session <application>psql</application> recevra la commande
<command>ABORT</command>, puis recherchera dans le fichier
<command>SYNC</command> un <command>COMMIT</command> ou un
<command>ROLLBACK</command> afin de continuer vers la prochaine
transaction.
</para>
<para>
Mais nous <emphasis>savons</emphasis> que la totalité du contenu du
fichier va échouer&nbsp;! Il est futile de continuer à analyser
le reste du fichier.
</para>
<para>
Voici une meilleure idée&nbsp;:
<itemizedlist>
<listitem>
<para>
Tout d'abord, lire les premières lignes du fichier, jusqu'à l'appel
à la fonction <function>setsyncTracking_offline()</function>.
</para>
</listitem>
<listitem>
<para>
Essayez de l'appliquer jusque là.
</para>
</listitem>
<listitem>
<para>
Si cela échoue, alors il est futile de continuer&nbsp;; lancez
un <command>ROLLBACK</command> sur la transaction, et essayez
éventuellement un autre fichier.
</para>
</listitem>
<listitem>
<para>
Si l'appel à <function>setsyncTracking_offline()</function>
fonctionne, alors vous avez trouver le bon fichier de
<command>SYNC</command> et vous pouvez l'appliquer. Vous devrez
probablement faire un <command>ROLLBACK</command> sur la
transaction, puis utiliser <application>psql</application> pour
appliquer la totalité des mises à jours contenues dans le fichier.
</para>
</listitem>
</itemizedlist>
</para>
<para>
Afin de faciliter la récupération des premières lignes des fichiers sync,
le format a été conçu pour qu'une ligne de pointillées indique la fin
de <quote>l'en-tête</quote>&nbsp;:
<programlisting>-- Slony-I log shipping archive
-- Node 11, Event 656
start transaction;
select "_T1".setsyncTracking_offline(1, '655', '656', '2007-09-23 18:37:40.206342');
-- end of log archiving header
</programlisting>
</para>
</listitem>
<listitem>
<para>
Notez que l'en-tête inclut l'horodatage qui témoigne de la date de
l'événement SYNC.
<programlisting>-- Slony-I log shipping archive
-- Node 11, Event 109
start transaction;
select "_T1".setsyncTracking_offline(1, '96', '109', '2007-09-23 19:01:31.267403');
-- end of log archiving header</programlisting>
</para>
<para>
Cet horodatage représente la date où le <command>SYNC</command> a été
déclenché sur le n&oelig;ud d'origine.
</para>
<para>
La valeur est stockée dans la table de configuration sl_setsync_offline.
</para>
<para>
Si vous construisez une base dynamique, cela représente probablement le
moment où vous voudrez appliquer toute les données d'une transaction de
log shipping.
</para>
</listitem>
<listitem>
<para>
Vous pouvez trouver plus d'informations sur comment l'activité du
n&oelig;ud est enregistré dans <xref linkend="logshiplog"/>.
</para>
</listitem>
</itemizedlist>
<para>
À partir de la version 1.2.11, il existe une méthode <emphasis>encore
meilleure</emphasis> pour appliquer les fichiers de journalisation car
leur règle de nommage est devenu plus compréhensible.
</para>
<itemizedlist>
<listitem>
<para>
Les traces, sur le n&oelig;ud de log shipping, qui indiquent le fichier
de journalisation le plus récemment traité, sont stockées dans la table
<envar>sl_archive_tracking</envar>.
</para>
<para>
Ainsi, vous pouvez prédire l'identifiant du prochain fichier de
journalisation en incrémentant le dernier identifiant de cette table.
</para>
</listitem>
<listitem>
<para>
Il existe néanmoins des variations dans le nommage des fichiers, en
fonction du nombre de n&oelig;uds qui composent le cluster. Tous les
n&oelig;uds produisent régulièrement des événements <command>SYNC</command>,
même s'ils ne sont pas le n&oelig;ud origine, et le système de log
shipping génère des logs pour ces événements.
</para>
<para>
En conséquence, lorsqu'on cherche le fichier de journalisation suivant,
il est nécessaire de chercher de la manière suivante&nbsp;:
<programlisting>ARCHIVEDIR=/var/spool/slony/archivelogs/node4
SLONYCLUSTER=mon_cluster
PGDATABASE=logshipdb
PGHOST=logshiphost
NEXTQUERY="select at_counter+1 from \"_${SLONYCLUSTER}\".sl_archive_tracking;"
nextseq=`psql -d ${PGDATABASE} -h ${PGHOST} -A -t -c "${NEXTQUERY}"
filespec=`printf "slony1_log_*_%20d.sql"
for file in `find $ARCHIVEDIR -name "${filespec}"; do
psql -d ${PGDATABASE} -h ${PGHOST} -f ${file}
done</programlisting>
</para>
</listitem>
</itemizedlist>
</sect2>
<sect2>
<title><application>find-triggers-to-deactivate.sh</application></title>
<indexterm><primary>désactivation des triggers</primary></indexterm>
<para>
Le <ulink url="http://www.slony.info/bugzilla/show_bug.cgi?id=19">bug
#19</ulink> indique que le dump d'un schéma peut contenir des triggers
et des règles que l'on ne souhaite pas activer sur un n&oelig;ud de log
shipping.
</para>
<para>
L'outil <filename> tools/find-triggers-to-deactivate.sh</filename> a été
créé pour assister l'utilisateur dans cette tache. Il peut être lancé sur un
n&oelig;ud qui sera utilisé comme schéma source, et il liste les règles et
les triggers, présents sur ce n&oelig;ud, qui devraient être désactivés.
</para>
<para>
Cela comprend le trigger <function>logtrigger</function> et
<function>denyaccess</function> qui sont normalement exclut du schéma extrait
avec pgdump. Il est toutefois de la responsabilité de l'administrateur de
vérifier que des triggers comme ceux-ci sont bien retirés du réplicat du log
shipping.
</para>
</sect2>
<sect2>
<title>L'outil <application>slony_logshipper</application></title>
<para>
À partir de la version 1.2.12, &slony1; a un outil conçu pour aider à
appliquer les logs, nommé <application>slony_logshipper</application>.
Il fonctionne avec trois types de paramètres&nbsp;:
</para>
<itemizedlist>
<listitem>
<para>des options&nbsp;:</para>
<itemizedlist>
<listitem><para><option>h</option></para> <para>affiche cette aide et se termine</para></listitem>
<listitem><para><option>v</option></para> <para>affiche la version et se termine</para></listitem>
<listitem><para><option>q</option></para> <para>mode silencieux</para></listitem>
<listitem><para><option>l</option></para> <para>ordonne au démon de rouvrir le fichier</para></listitem>
<listitem><para><option>r</option></para> <para>ordonne au démon de continuer après une erreur</para></listitem>
<listitem><para><option>t</option></para> <para>ordonne au démon d'entrer en mode d'arrêt intelligent ("smart shutdown")</para> </listitem>
<listitem><para><option>T</option></para> <para>ordonne au démon d'entrer en mode d'arrêt immédiat</para></listitem>
<listitem><para><option>c</option></para> <para>détruit les sémaphores existantes et la file d'attente des messages (utiliser avec précaution)</para></listitem>
<listitem><para><option>f</option></para> <para>reste au premier plan (ne fonctionne pas en mode démon)</para></listitem>
<listitem><para><option>w</option></para> <para>entre immédiatement en mode d'arrêt intelligent</para></listitem>
</itemizedlist>
</listitem>
<listitem>
<para>un fichier de configuration spécifique</para>
<para>Ce fichier est composé des paramètres suivants&nbsp;:</para>
<itemizedlist>
<listitem>
<para><command>logfile = './offline_logs/logshipper.log';</command></para>
<para>L'endroit où le log shipper laissera ses traces d'exécutions.</para>
</listitem>
<listitem>
<para><command>cluster name = 'T1';</command></para>
<para>le nom du cluster</para>
</listitem>
<listitem>
<para><command>destination database = 'dbname=slony_test3';</command></para>
<para>
Le paramètre conninfo optionnel pour se connecter à la base
destination. Si ce paramètre est fourni, le log shipper se connectera
à cette base et y appliquera les fichiers de journalisation.
</para>
</listitem>
<listitem>
<para><command>archive dir = './offline_logs';</command></para>
<para>
Le répertoire d'archive est obligatoire lorsqu'on est en mode
<quote>connecté à une base de données</quote> afin de pouvoir
parcourir un n&oelig;ud à la recherche d'archives manquantes (ou non appliquées).
</para>
</listitem>
<listitem>
<para><command>destination dir = './offline_result';</command></para>
<para>
Si ce paramètre est défini, le log shipper écrira les résultats du
traitement des données à l'intérieur de fichiers de journalisation
placés dans ce répertoire.
</para>
</listitem>
<listitem>
<para><command>max archives = 3600;</command></para>
<para>
Ce paramètre lutte contre d'éventuelles fuites mémoire&nbsp;; le
démon entrera en mode d'arrêt intelligent(<quote>smart shutdown</quote>)
automatiquement après avoir traité ce nombre d'archives.
</para>
</listitem>
<listitem>
<para><command>ignore table "public"."history";</command></para>
<para>
On peut exclure certaines tables du système de log shipping.
</para>
</listitem>
<listitem>
<para><command>ignore namespace "public";</command></para>
<para>
On peut exclure un espace de noms du système de réplication.
</para>
</listitem>
<listitem>
<para><command>rename namespace "public"."history" to "site_001"."history";</command></para>
<para>
On peut renommer des tables spécifiques.
</para>
</listitem>
<listitem>
<para><command>rename namespace "public" to "site_001";</command></para>
<para>
On peut renommer un espace de noms.
</para>
</listitem>
<listitem>
<para>
<command>post processing command = 'gzip -9 $inarchive';</command>
</para>
<para>
Les commandes de pré-traitement et post-traitement sont exécutées
via la fonction <function>system(3)</function>.
</para>
</listitem>
</itemizedlist>
<para>
Un <quote>@</quote> placé devant le nom de la commande permet d'ignorer
un code de retour. Sinon, tout code de retour différent de zéro sera
traité comme une erreur et provoquera l'arrêt du processus.
</para>
<para>
Par ailleurs, les commandes de pré-traitement et de post-traitement ont
accès à deux variables spéciales&nbsp;:
</para>
<itemizedlist>
<listitem><para><envar>$inarchive</envar> - indique le nom du fichier d'archive en entrée</para></listitem>
<listitem><para><envar>$outnarchive</envar> - indique le nom du fichier d'archive en sortie</para></listitem>
</itemizedlist>
</listitem>
<listitem>
<para><command>error command = ' ( echo "archive=$inarchive" echo "error messages:" echo "$errortext" ) | mail -s "Slony log shipping failed" postgres@localhost ';</command></para>
<para>
La commande d'erreur indique quelle commande lancer lorsqu'une erreur est
rencontrée. Tout l'archivage réalisé depuis le dernier archivage traité
avec succès est disponible dans la variable <envar>$errortext</envar>.
</para>
<para>
Dans l'exemple donné, un courriel est envoyé à l'administrateur lorsqu'une
erreur est rencontrée.
</para>
</listitem>
</itemizedlist>
<itemizedlist>
<listitem>
<para>Noms des fichiers d'archive</para>
<para>
Chaque nom de fichier est ajouté à la file d'attente des messages SystemV
afin qu'un processus <application>slony_logshipper</application> le
traite.
</para>
</listitem>
</itemizedlist>
</sect2>
</sect1>