Find file
Fetching contributors…
Cannot retrieve contributors at this time
317 lines (270 sloc) 11.6 KB
<?xml version="1.0" encoding="UTF-8"?>
<!-- Dernière modification
le $Date$
par $Author$
révision $Revision$ -->
<sect1 id="definingsets">
<title>Définir les ensembles de réplication</title>
<indexterm><primary>définir les ensembles de réplication</primary></indexterm>
<para>
En définissant les n&oelig;uds, on a conçu l'architecture du cluster de
réplication&nbsp;; il est temps de déterminer quelles données doivent être
copiées entre les n&oelig;uds. Les groupes de données qui sont copiés sont
nommés <quote>ensembles de réplication</quote>.
</para>
<para>
Un ensemble de réplication comprend&nbsp;:
</para>
<itemizedlist>
<listitem>
<para>
Les clefs des tables à répliquer qui n'ont pas de clef primaire
possible&nbsp;;
</para>
</listitem>
<listitem>
<para>
Les tables qui doivent être répliquées&nbsp;;
</para>
</listitem>
<listitem>
<para>
Les séquences qui doivent être répliquées.
</para>
</listitem>
</itemizedlist>
<sect2><title>Les clefs primaires</title>
<indexterm><primary>importance des clefs primaires</primary></indexterm>
<para>
&slony1; <emphasis>a besoin</emphasis> d'une clef primaire ou d'un ensemble
de champ éligible au statut de clef primaire pour chacune des tables qui
seront répliquées. Les valeurs de clefs primaires (acronyme «&nbsp;PK&nbsp;»)
sont utilisées comme identifiant primaire pour chaque ligne qui est modifiée
sur le système source. Notons que les clefs primaires peuvent être des clefs
composées de plusieurs colonnes NOT NULL&nbsp;; elles ne doivent pas
obligatoirement être constituées de champs uniques. Il y a trois façons de
préciser à &slony1; quelle clef primaire utiliser&nbsp;:
</para>
<itemizedlist>
<listitem>
<para>
Si la table a déjà une clef primaire identifiée, <xref
linkend="stmtsetaddtable"/> peut être utilisé sans qu'il soit nécessaire
de préciser la clef primaire. &slony1; peut automatiquement comprendre
qu'il existe une clef primaire et l'utiliser.
</para>
</listitem>
<listitem>
<para>
Si la table ne dispose pas d'une clef primaire mais a une clef primaire
<emphasis>candidate</emphasis>, c'est-à-dire un index sur une combinaison
de champs qui sont à la fois UNIQUE et NOT NULL, alors vous pouvez
spécifier cette clef comme ceci&nbsp;:
</para>
<programlisting>
SET ADD TABLE (set id = 1, origin = 1, id = 42,
full qualified name = 'public.ma_table',
key = 'ma_table_idx',
comment='ma_table_idx est une clef primaire candidate de ma_table');
</programlisting>
<para>
Cependant, une fois arrivé à cette étape, pourquoi ne pas déclarer l'index
comme une clef primaire, ce qui nécessite que les colonnes impliquées soient
NOT NULL, et ce qui constituera un index unique. Voici un exemple&nbsp;:
</para>
<programlisting>
DROP INDEX ma_table_nom_col1_col2_uniq_idx;
ALTER TABLE ma_table_nom ADD PRIMARY KEY (col1, col2);
</programlisting>
<para>
Si votre application utilise l'index ma_table_nom, vous ne perdrez rien et
cela vous donnera l'avantage d'avoir une clef primaire sur votre table.
</para>
<para>
Notons que si vous devez spécifier un espace de nom («&nbsp;namespace&nbsp;»)
pour la table, vous <emphasis>ne devez pas</emphasis> préciser l'espace de
nom de la clef car cela peut interférer avec d'autres espaces de noms de la
table.
</para>
</listitem>
<listitem>
<para>
Si la table n'a pas de clef primaire candidate, vous devez demander à
&slony1; d'en produire une en utilisant la commande <xref
linkend="stmttableaddkey"/>.
</para>
<warning>
<para>
La commande <xref linkend="stmttableaddkey"/> a toujours été considérée
au mieux comme un <quote>bricolage</quote>, et à partir de la version
2.0, elle est considérée comme une mauvaise fonctionnalité qu'il faut
supprimer.
</para>
</warning>
</listitem>
</itemizedlist>
<para>
Il n'est pas terriblement important de sélectionner une <quote>vraie</quote>
clef primaire ou une simple <quote>clef primaire</quote>. Cependant, il est
fortement recommandé d'utiliser une de ces deux solutions plutôt que de
laisser &slony1; remplir la colonne de clef primaire à votre place. Si vous
n'avez pas de clef primaire candidate, cela signifie que la table ne fournit
aucun mécanisme à votre application pour garder les lignes uniques. Dans ce
cadre, &slony1; peut introduire des erreurs dans votre application. De plus,
cela implique que vous pouvez entrer des données erronées dans la base de
données.
</para>
</sect2>
<sect2 id="definesets">
<title>Regrouper les tables en ensembles</title>
<indexterm><primary> grouper les tables dans des ensembles de réplication </primary></indexterm>
<para>
Il est vital de regrouper les tables dans un seul ensemble lorsque ces tables
sont reliées par une clef étrangère. Si des tables reliées de cette manière
ne sont <emphasis>pas</emphasis> répliquées ensembles, vous rencontrerez des
problèmes lors de la bascule du n&oelig;ud <quote>fournisseur maître</quote>
vers un autre n&oelig;ud, et vous obtiendrez un nouveau <quote>maître</quote>
qui ne peut pas être mis à jour correctement car le contenu de certaines
tables n'est pas disponible.
</para>
<para>
Il y a également plusieurs raisons pour ne <emphasis>pas</emphasis> placer
toutes les tables dans un ensemble unique&nbsp;:
</para>
<itemizedlist>
<listitem>
<para>
Sur un ensemble très large, l'événement initial
<command>COPY_SET</command> provoque de <link
linkend="longtxnsareevil">très longues transactions</link> sur le
n&oelig;ud fournisseur. La <link linkend="faq">FAQ</link> décrit un
certain nombre de problèmes qui conduisent à des transactions qui
ralentissent les performances du système.
</para>
<para>
Si vous pouvez découper un grand ensemble en plusieurs plus petits
ensembles, cela réduira la longueur de chaque transactions et diminuera
leur impact négatif sur les performances.
</para>
<para>
Un autre problème survient fréquemment lorsque l'on réplique via un
WAN&nbsp;; parfois la connexion réseau est un peu instable, si bien
qu'il y a des risques qu'une connexion reste ouverte pendant plusieurs
heures et entraîne un <command>CONNECTION TIMEOUT</command>. Si cela se
produit à 95% d'une copie d'un ensemble de réplication de 50 tables,
représentant 250GB de données, cela va gâcher votre journée. Au contraire
si les tables sont séparées en plusieurs ensembles de réplication, cette
panne réseau qui intervient à 95% n'interrompra que la copie
d'<emphasis>un seul</emphasis> ensemble.
</para>
<para>
Certains <quote>effets négatifs</quote> surviennent lorsque la base de
données répliquée contient plusieurs Go de données, et qu'il faut des
heures ou des jours pour qu'un n&oelig;ud abonné réalise une copie
complète des données initiales. Pour les bases relativement petites,
cela n'est pas un facteur important.
</para>
</listitem>
<listitem>
<para>
Chaque invocation de la commande <xref linkend="stmtddlscript"/>
nécessite un verrou sur <emphasis>chaque table de l'ensemble de
réplication, d'abord sur le n&oelig;ud d'origine puis, avec la
propagation de l'événement, sur chacun des n&oelig;uds abonnés
</emphasis>.
</para>
<para>
Des retours d'expériences <quote>de terrain</quote> indiquent que cela
peut conduire à des inter-blocages de verrous ("deadlocks"), ce qui
nécessite d'appeler la requête <xref linkend="stmtddlscript"/> plusieurs
fois pour réussir à l'exécuter complètement.
</para>
<para>
Plus vous avez de tables dans un ensemble de réplication, plus ces tables
doivent être verrouillées et plus les risques d'obtenir un inter-blocage
des verrous sont importants.
</para>
<para>
Dans le même ordre d'idées, si un script DDL particulier doit simplement
affecter deux tables, vous devez utiliser <xref
linkend="stmtsetmovetable"/> pour les déplacer temporairement dans un
nouvel ensemble de réplication. En diminuant le nombre de verrous
nécessaire, cela simplifiera la mise en place des changements DDL.
</para>
<para>
Il y a de plus amples <link linkend="locking">discussions sur les
verrous</link> qui décrivent quand &slony1; a besoin de verrous et leur
impact sur vos applications.
</para>
</listitem>
</itemizedlist>
</sect2>
<sect2> <title>Pathologie des séquences</title>
<indexterm><primary>Pathologie de séquence</primary></indexterm>
<para>
Chaque fois qu'un évènement SYNC est traité, les valeurs sont enregistrées
pour <emphasis>toutes</emphasis> les séquences de l'ensemble de réplication.
Si vous avez beaucoup de séquences, cela peut augmenter fortement la
volumétrie de la table &slseqlog;.
</para>
<para>
Cela illustre une différence importante entre les tables et les
séquences&nbsp;: si vous ajoutez des tables supplémentaire qui ont peu
d'activité, voire aucune, cela n'ajoute pas de charge supplémentaire pour le
système de réplication. Pour les séquences répliquées, les valeurs doivent
être <emphasis>régulièrement</emphasis> propagées aux abonnés. Considérons
les conséquences&nbsp;:
<itemizedlist>
<listitem>
<para>
Une table répliquée mais qui n'est jamais mise à jour n'entraîne pas
de travail supplémentaire.
</para>
<para>
Si elle n'est jamais mise à jour, le trigger de la table sur le
n&oelig;ud origine n'est jamais déclenché, et aucune entrée n'est
ajoutée dans &sllog1;/&sllog2;. La table n'apparaît
jamais dans aucune des requêtes de réplication (<emphasis>par
exemple&nbsp;:</emphasis> dans les requêtes <command>FETCH 100 FROM
LOG</command> utilisées pour trouver les données à répliquer) car elles
ne recherchent que les tables qui ont des entrées dans
&sllog1;/&sllog2;.
</para>
</listitem>
<listitem>
<para>
Au contraire, une certaine quantité de travail est ajoutée lors d'un
événement SYNC pour chaque séquence qui est répliquée.
</para>
<para>
Pour répliquer 300 séquences, 300 lignes doivent être ajoutées dans la
&slseqlog; de manière régulière, au moins jusqu'à la branche 2.0 où les
mises à jour sont seulement appliquées quand la valeur d'une séquence
données est visible modifiée.
</para>
<para>
Il est probable que si une valeur d'une séquence particulière n'a pas
changé depuis la dernière vérification, alors il n'est peut-être pas
nécessaire de stocker cette valeur encore et encore. Certaines
reflexions sont en cours sur le moyen de réaliser cela de manière
sécurisée.
</para>
</listitem>
<listitem>
<para>
Le <ulink
url="http://gborg.postgresql.org/project/slony1/bugs/bugupdate.php?1226">
bug #1226</ulink> indique une condition d'erreur qui peut se produire
si vous avez un ensemble de réplication composé uniquement de séquences.
</para>
<para>
Ceci est documenté plus précisément dans la <link
linkend="sequenceset">FAQ</link>. En résumé, avoir un ensemble de
réplication composé uniquement de séquences n'est pas particulièrement
une bonne idée.
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
</sect1>