Ces questions ne sont pas toutes, au sens strict, des questions « fréquemment posées » ; certaines illustrent des problèmes identifiés qu'il semble bon de documenter.
1. FAQ de Slony-I™ : compiler et installer Slony-I™ |
|
|
1.1. |
J'utilise Frotznik Freenix 4.5™ avec son système de gestion de paquetages FFPM (Frotznik Freenix Package Manager). Il existe des paquets FFPM pour PostgreSQL™ 7.4.7, que j'utilise actuellement comme base de données, mais il n'y a pas encore de paquetages Slony-I™. Comment puis-je rajouter Slony-I™ à cette distribution ? |
|
Frotznik Freenix™ est nouveau pour moi, alors il est un peu dangereux de donner une réponse définitive, concise et rapide. Les réponses différent légèrement selon les diverses combinaisons de versions entre PostgreSQL™ et Slony-I™ Il est légèrement plus facile, avec les versions récentes, de faire face à ce genre de questions qu'avec des versions plus anciennes. En général, vous devez presque certainement recompiler Slony-I™ depuis les sources. Selon les versions des deux composants Slony-I™ et PostgreSQL™, vous devez également recompiler PostgreSQL™ à partir de zéro. (Savoir si vous devez utiliser la version compilée de PostgreSQL™ est un autre problème mais en général ce n'est pas le cas...)
En pratique, la « pire situation » est un scénario où vous utilisez une version de Slony-I™ antérieure à 1.1 avec une « vieille » version de PostgreSQL™. Dans ce cas, vous devez compiler PostgreSQL™ à partir de zéro afin d'avoir tous les pré-requis de compilation de Slony-I™ même si vous utilisez une version « packagée » de PostgreSQL™. Si vous utilisez une version récente de PostgreSQL™ et une version récente de Slony-I™, alors les dépendences peuvent être assez faibles, et vous n'avez pas besoin de fichiers sources complémentaires.Ces améliorations devraient soulager la mise en production des paquets de Slony-I™ de sorte que vous pourriez même pouvoir espérer éviter la compilation de Slony-I™. |
|
|
1.2. |
J'essaie d'installer Slony-I™ 1.1 et j'obtiens le message d'erreur suivant : configure: error: Headers for libpqserver are not found in the includeserverdir. This is the path to postgres.h. Please specify the includeserverdir with --with-pgincludeserverdir=<dir> |
|
Vous exécutez certainement une version 7.4 de PostgreSQL™ ou une version antérieure. Une version où les en-têtes de serveur ne sont pas installés par défaut. Dans ce cas, il vous suffit de lancer la commande make install de PostgreSQL™. Vous devez installer les en-têtes du serveur lors d'installation de PostgreSQL™ via la commande make install-all-headers. |
|
|
1.3. |
Slony-I™ semble se compiler correctement ; maintenant, lorsque j'exécute un slon(1), certains évènements se déclenchent, mais la réplication ne se met pas route. Les journaux applicatifs de Slony ressemblent à ça :
DEBUG1 remoteListenThread_1: connected to 'host=host004 dbname=pgbenchrep user=postgres port=5432'
ERROR remoteListenThread_1: "select ev_origin, ev_seqno, ev_timestamp,
ev_minxid, ev_maxxid, ev_xip,
ev_type,
ev_data1, ev_data2,
ev_data3, ev_data4,
ev_data5, ev_data6,
ev_data7, ev_data8 from "_pgbenchtest".sl_event e
where (e.ev_origin = '1' and e.ev_seqno > '1') order by e.ev_origin, e.ev_seqno" - could not receive data from server: Operation now in progress
Parfois, ils contiennent les lignes suivantes... ERROR remoteListenThread_2: "select ev_origin, ev_seqno, ev_timestamp, ev_minxid, ev_maxxid, ev_xip, ev_type, ev_data1, ev_data2, ev_data3, ev_data4, ev_data5, ev_data6, ev_data7, ev_data8 from "_sl_p2t2".sl_event e where (e.ev_origin = '2' and e.ev_seqno > '0') order by e.ev_origin, e.ev_seqno" - could not receive data from server: Error 0 |
|
Sur AIX et Solaris (et probablement sur d'autres OS), Slony-I™ et PostgreSQL™ doivent être compilés avec l'option --enable-thread-safety. Le message ci-dessus arrive lorsque la compilation de PostgreSQL™ n'a pas fait appel à cette option. Le disfonctionnement ici vient du fait que la bibliothèque C (indépendante des threads) et la bibliothèque de PostgreSQL™, libpq, (basée sur les threads) utilisent des emplacements de mémoire différents pour les codes d'erreur. Cela fait échouer les requêtes. Des problèmes de ce genre surviennent avec des régularités surprenantes sur AIX et sur Solaris. Il sera probablement nécessaire de réaliser un « audit du code objet » pour s'assurer que tous les composants nécessaires ont été compilés et liés avec l'option --enable-thread-safety. Par exemple, on peut rencontrer un problème sur Solaris lorsque LD_LIBRARY_PATH est défini et pointe sur les bibliothèques depuis une ancienne version compilée de PostgreSQL™. Cela signifie que même si la base de donnée avait été compilée avec l'option --enable-thread-safety, et même si slon a été recompilé pour cette version, lors de l'édition de liens dynamique, slon pointait sur une « ancienne et mauvaise version compilée sans l'option thread-safe, », slon ne fonctionne pas. On ne peut s'apercevoir de cela qu'en exécutant ldd sur slon. |
|
|
À noter que la version 7.4.2 de libpq sur Solaris nécessite un patch supplémentaire pour les threads. Ce pré-requis est également demandé pour PostgreSQL™ version 8.0. |
|
|
1.4. |
Je suis en train de migrer sur une nouvelle version de Slony-I™ et je me débat avec un problème sur SLONIK UPDATE FUNCTIONS(7). Lors de l'exécution de SLONIK UPDATE FUNCTIONS(7), mon postmaster s'arrête brutalement avec le signal 11. Le journal applicatif ne contient aucune erreur, exceptées celles relatives à PostgreSQL™. Les journaux applicatifs indiquent simplement que le postmaster est bel bien arrêté. En scrutant le fichier core avec un déboggueur, on constate que l'incident survient lors de la validation d'une transaction. Pour infos je suis sur PostgreSQL™ 8.1.[0-3]. |
|
Malheureusement, les anciennes versions de PostgreSQL™ 8.1 avaient un problème lors de la re-définition d'une fonction (par exemple upgradeSchema(text)), lorsque la fonction est appellée juste après, au sein de la même transaction, le postmaster plante et la transaction est annulée. La commande slonik(1) SLONIK UPDATE FUNCTIONS(7) fonctionne de cette manière ; dans une même transaction, elle effectue ceci : Malheureusement, avec PostgreSQL™ 8.1.0, 8.1.1, 8.1.2, et 8.1.3, ceci est conflictuel avec un bogue où l'utilisation et la modification d'une fonction plpgsql au sein de la même transaction provoque un arrêt brutal. Plusieurs contournements sont envisageables. |
|
|
La meilleure solution consiste à migrer PostgreSQL™ vers une version 8.1.4 ou supérieure. Les changements entre deux versions mineures ne nécessitent pas la reconstruction de la base, il suffit simplement d'installer la nouvelle version, puis de redémarrer le postmaster avec cette nouvelle version. |
|
|
Si cette solution ne convient pas, il est possible d'effectuer la mise à jour via une série de transactions « à la main », qui correspondent à ce que slonik(1) aurait fait pour cette migration.
|
|
|
1.5. |
Problème d'installation sur Fedora/x86-64 Lorsqu'on essaie de configurer Slony-I™ sur un système Fedora x86-64, où yum a été utilisé pour une installation du paquetage postgresql-libs.x86_64, le message suivant se manifeste : configure: error: Your version of libpq doesn't have PQunescapeBytea this means that your version of PostgreSQL is lower than 7.3 and thus not supported by Slony-I. Ceci arrive avec PostgreSQL™ 8.2.5, qui est nettement plus récent que la version 7.3. |
|
La fonction configure est à la recherche du symbole PQunescapeBytea. Elle compile un petit programme qu'il exécute et vérifie que la compilation se passe bien. Dans la ligne de commande gcc, elle utilise -lpq pour ajouter la bibliothèque. Malheureusement, ce paquetage n'a pas de lien symbolique, reliant /usr/lib64/libpq.so à libpq.so.5.0 ; c'est pourquoi la fonction configure n'arrive pas à trouver libpq. Le vrai problème, c'est que le compilateur n'arrive pas à trouver une bibliothèque pour l'édition des liens, et non pas que libpq ait manqué à l'appel. Au final, ces informations doivent être envoyée vers ceux qui gèrent le paquet postgresql-libs.x86_64. |
|
|
Notez que ce même symptôme peut être révélateur d'autres problèmes de ce genre au niveau de la configuration système. Les mauvais liens symboliques, les mauvais droits, le mauvais comportement de la part de votre compilateur C, tous peuvent potentiellement mener à ce même message d'erreur. Ainsi, si vous rencontrez cette erreur, vous aurez besoin de regarder le fichier de traces nommé config.log. Cherchez à partir du bas, et regardez quel souci est réellement rencontré. Ceci sera utile pour trouver la vraie racine de cet épineux problème. |
|
|
1.6. |
J'ai trouvé des types en conflit pour yyleng entre parser.c et scan.c. Dans un cas, le type int était en conflit avec le type yy_size_t. Que puis-je faire ? |
|
Ceci a déjà été observé sur MacOS où flex (qui génère scan.c) et bison qui génère parser.c) divergent dans leur gestion de cette variable.
|
|
2. FAQ Slony-I™ : Comment puis-je ? |
|
|
2.1. |
J'ai besoin de sauvegarder une base de données sans la configuration de Slony-I™ (autrement dit sans triggers, fonctions, etc). |
|
Jusqu'à la version 1.2, ce n'est pas trivial et demande un choix attentif des nœuds et quelques « procédures » modérément conséquente. Voici une méthode :
|
|
|
Avec Slony-I™ 2.0, la réponse est plus simple : prenez seulement une sauvegarde de type pg_dump --exclude-schema=_Cluster sur un nœud quelqu'il soit. En 2.0, les schémas ne sont plus corrompus, donc une sauvegarde simple avec pg_dump doit faire ce que vous voulez. |
|
|
2.2. |
J'aimerais renuméroter les nœuds de mon cluster. Comment puis-je le faire ? |
|
Une première réponse est « ne faites pas ça » - les numéros des nœuds Slony-I™ ne sont « pas modifiables ». Les numéros de nœuds sont utilisés partout dans le schéma. Ils sont indiqués dans pratiquement toutes les tables systèmes de Slony. Encore plus important, ils sont utilisés comme base de tout événement de propagation. La seule fois où il pourrait être « convenable » de modifier un numéro de nœud est au moment où nous savons qu'il n'est pas utiliser et nous aurons besoin de faire les mises à jour sur chaque nœud dans le cluster d'une façon organisée. Automatiser cette manipulation est un énorme challenge, car les changements se font sur la structure du système de propagation des événements qui a déjà besoin de fonctionner pour qu'un tel changement soit propagé. |
|
|
Si c'est absolument nécessaire de renuméroter les nœuds, cela peut se faire en supprimant puis en rajoutant les nœuds pour se débarrasser de l'identifiant de nœud nécessaire. |
|
3. FAQ Slony-I™ : ce que les gens testent mais ne devraient pas |
|
|
3.1. |
Puis-je utiliser Slony-I™ pour fait du multi-maître ? |
|
À un simple niveau, il est théoriquement possible de le faire si vous concevez votre application de façon à ce que chaque maître a son propre ensemble distinct de tables et que vous disposiez d'un moyen pour consolider les données et qu'elles aient une vue commune. Néanmoins, ceci requiert une grande attention dans la création de l'application pour réaliser cette consolidation. |
|
|
En pratique, le terme utilisé est « réplication multi-maître » et Slony-I™ ne permet pas de le faire. |
|
|
3.2. |
Je veux répliquer toutes les bases de données d'un système partagé que je gère. Il existe plusieurs bases de données, utilisées par mes clients. |
|
Pour cela, une méthode comme PITR (Point In Time Recovery) proposée par PostgreSQL™ semble mieux convenir. Slony-I™ nécessite un démon (et plusieurs connexions pour chaque base de données identifiables. Si vous avez une instance PostgreSQL™ comprenant 50 ou 100 bases de données, cela va nécessiter des centaines de connexions aux bases. Typiquement, dans des situations d'« hébergement partagé », les modifications de schéma sont gérées par les clients qui peuvent changer tout ce qu'ils souhaitent quand ils le souhaitent. Slony-I™ ne fonctionne pas bien lorsqu'il est utilisé d'une manière non discipliné. |
|
|
3.3. |
Je veux pouvoir faire des modifications de structure de ma base et que ces modifications soient automatiquement répliquées. |
|
Slony-I™ requiert que les Section 17, « Changements du schéma de la base (DDL) » soit préparées avec attention. Slony-I™ capture les modifications en utilisant des triggers et PostgreSQL™ ne fournit aucun moyen pour capturer des modifications de schéma par des triggers.
NoteIl y a eu des discussions sur ce sujet pour essayer de faire en sorte que PostgreSQL™ puisse récupérer les modifications de schéma d'une façon qui permettrait l'utilisation de triggers ; rien de concret n'est apparu depuis cette discussion qui date de quelques années. |
|
|
3.4. |
Je veux diviser mon cluster en partitions disjointes qui ne sont pas conscientes des autres. Slony-I™ continue à générer les Section 9, « Voix d'écoute » qui lient les partitions entre elles. |
|
Le fait que tous les nœuds sont conscients des autres est intégré profondément dans le design de Slony-I™. Par exemple, sa gestion du nettoyage des données obsolètes dépend de la connaissance du lag des autres nœuds. |
|
|
3.5. |
Je veux changer certains des numéros de nœuds. Comment puis-je « renommer » un nœud pour avoir un différent numéro de nœud ? |
|
Vous ne pouvez pas. Le numéro de nœud est utilisé pour coordonner les communications inter-nœuds. Changer le numéro de nœud « en ligne » pourrait rendre impossible la coordination de la configuration du nœud. |
|
|
3.6. |
Mon application utilise les attributs OID ; est-il possible de répliquer ce type de tables ? |
|
Il est intéressant de noter que les OID, comme attribut d'une table utilisateur, ont été rendus obsolètes depuis la version 8.1 de PostgreSQL™, autrement dit depuis 2005. Slony-I™ n'a jamais utilisé les OID pour la réplication. Cette fonctionnalité étant devenu obsolète, les développeurs n'ont aucune intention d'ajouter son utilisation. PostgreSQL™ a implémenté les OID pour lier les catalogues systèmes entre eux ; les utiliser avec les tables utilisateurs est considéré comme une mauvaise pratique, et il est recommandé d'utiliser une séquence pour peupler votre colonne d'identifiant dans les tables utilisateurs. |
|
|
Bien sûr, rien ne vous empêcher de créer une table sans OID, puis d'ajouter votre propre colonne appelée oid, de préférence avec l'information SERIAL NOT NULL UNIQUE, qui peut être répliquée, et qui peut être utilisé comme clé primaire pour la table. |
|
4. Slony-I™ FAQ: Problèmes relatifs aux connections |
|
|
4.1. |
Je cherche le namespace _clustername, mais il est introuvable. |
|
Si les DNS sont erronés, alors l'instance slon(1) ne pourra pas se connecter aux nœuds. Ceci mène au fait que les nœuds seront introuvables. Vérifier de nouveau la configuration des connexions. D'ailleurs, puisque slon(1) est lié à libpq, vous pouvez stocker le mot de passe dans $HOME/.pgpass, le problème vient peut-être d'une erreur dans ce fichier. |
|
|
4.2. |
J'ai créé un compte « super-utilisateur », slony, pour exécuter les activités de réplication. Comme suggéré, je l'ai configuré comme super-utilisateur, avec la requête suivante : UPDATE pg_shadow SET usesuper = 't' WHERE usename IN ('slony', 'molly', 'dumpy'); (Cette même commande permet d'autoriser autres utilisateurs à exécuter VACUUM et sauvegardes). Malheureusement, j'ai eu une erreur à chaque fois où je voulais souscrire à un nouveau ensemble. DEBUG1 copy_set 28661 DEBUG1 remoteWorkerThread_1: connected to provider DB DEBUG2 remoteWorkerThread_78: forward confirm 1,594436 received by 78 DEBUG2 remoteWorkerThread_1: copy table public.billing_discount ERROR remoteWorkerThread_1: "select "_mycluster".setAddTable_int(28661, 51, 'public.billing_discount', 'billing_discount_pkey', 'Table public.billing_discount with candidate primary key billing_discount_pkey'); " PGRES_FATAL_ERROR ERROR: permission denied for relation pg_class CONTEXT: PL/pgSQL function "altertableforreplication" line 23 at select into variables PL/pgSQL function "setaddtable_int" line 76 at perform WARN remoteWorkerThread_1: data copy for set 28661 failed - sleep 60 seconds Cela continue de s'arrêter avec une erreur, encore et toujours, jusqu'à ce que je redémarre slon pour qu'il se connecte avec le compte postgres. |
|
Le problème est assez évident en soi ; le droit sur la table système pg_class est ignoré. |
|
|
La « solution » est la suivante : UPDATE pg_shadow SET usesuper = 't', usecatupd='t' WHERE usename = 'slony'; |
|
|
En version 8.1 et supérieure, vous avez aussi besoin de : UPDATE pg_authid SET rolcatupdate = 't', rolsuper='t' WHERE rolname = 'slony'; |
|
|
4.3. |
Au moment d'enregistrer un esclave, j'obtiens le message suivant dans les journaux applicatifs : DEBUG1 copy_set 1 DEBUG1 remoteWorkerThread_1: connected to provider DB WARN remoteWorkerThread_1: transactions earlier than XID 127314958 are still in progress WARN remoteWorkerThread_1: data copy for set 1 failed - sleep 60 seconds |
|
Il y a évidemment un certain nombre de vieilles transactions qui empêchent Slony-I™ de traiter des synchronisations. Vous devriez jeter un coup d'œil à pg_locks pour voir ce qu'il en est :
sampledb=# select * from pg_locks where transaction is not null order by transaction;
relation | database | transaction | pid | mode | granted
----------+----------+-------------+---------+---------------+---------
| | 127314921 | 2605100 | ExclusiveLock | t
| | 127326504 | 5660904 | ExclusiveLock | t
(2 rows)
Vous voyez ? la transaction 127314921 est en effet plus vieille que la transaction 127314958, et elle est toujours en cours d'exécution. Un long traitement de publi-postage, une requête RT3 qui s'emballe, un pg_dump, toutes ces opérations ouvrent des transactions pour une période importante. Jusqu'à ce qu'elles soient complétées ou bien interrompues, on verra alors le message d'erreur suivant : « data copy for set 1 failed - sleep 60 seconds » Quoiqu'il en soit, s'il y a plus d'une base de données sur le cluster PostgreSQL™ et que la charge se situe sur une autre base, vous verrez apparaître des « transactions en cours avec un XID antérieur » à celle de Slony-I™. Le fait que la transaction se déroule sur une base de donnée dissociée ne change rien ; Slony-I™ attendra jusqu'à ce que ces vieilles transactions se terminent. |
|
|
4.4. |
Même question que précèdemment. J'ai oublié de mentionner que j'essayais d'ajouter DEUX abonnés simultanément. |
|
Cela ne peut pas fonctionner : Slony-I™ ne peut employer pas la commande COPY de manière concurrente. Voir la fonction copy_set() dans le fichier src/slon/remote_worker.c. $ ps -aef | egrep '[2]605100' postgres 2605100 205018 0 18:53:43 pts/3 3:13 postgres: postgres sampledb localhost COPY Une transaction COPY essaie d'installer l'abonnement pour un des nœuds. Tout a l'air bien ; le système s'occupe de configurer le premier abonné ; il ne va pas démarrer sur le second tant que le premier n'a pas fini son enregistrement. Cela représente une cause possible. Ceci a comme (fâcheuse) conséquence que vous ne pouvez pas peupler deux esclaves simultanément à partir d'un même fournisseur. Vous devez souscrire un et un seul abonné à la fois. Une fois qu'il a accompli l'abonnement (en copiant le contenu des table, etc.), on peut s'occuper de débuter l'enregistrement du deuxième. |
|
|
4.5. |
Nous avons rencontré un message inattendu en désinstallant entièrement un cluster de réplication slony sur le maître et l'esclave.
AvertissementMAKE SURE YOU STOP YOUR APPLICATION RUNNING AGAINST YOUR MASTER DATABASE WHEN REMOVING THE WHOLE SLONY CLUSTER, or at least re-cycle all your open connections after the event! Les connexions « se rappelent » ou font référence aux OID qui sont supprimés par le script de déinstallation du nœud. C'est la cause d'un grand nombre d'erreurs... |
|
Il y a deux mécanismes de PostgreSQL™ qui mettent en cache les plans d'interrogation et les OIDs :
Ce problème n'est pas particulier à Slony-I™; il se produit à chaque fois que des modifications importantes sont apportées aux schémas de la base de données. Cela n'entraîne pas de perte des données mais cela provoque des vagues d'erreurs relatives aux OID. |
|
|
Le problème survient lorsque vous utilisez une sorte de « pool de connexion » qui recycle les vieilles connexions. Si vous relancez l'application après ceci, les nouvelles connexions vont produire de nouveaux plans d'exécution et les erreurs disparaîtront. Si votre pool de connexion tue les sessions et en recrée de nouvelles, alors ces nouvelles sessions auront de nouveaux plans d'exécution et les erreurs disparaîtront. |
|
|
Dans notre code, nous éliminons toutes connexions ayant des erreurs inattendues dans le contexte. Ainsi, toutes les connexions devraient être renouvelées dès l'apparition d'une erreur inattendue. Naturellement, si l'erreur remonte une violation de contrainte, qui est une condition reconnue, cela va provoquer un renouvellement de connexion. Si le problème persiste, les connexions sont recyclées en permanence, ce qui annulera l'effet du pool. Dans ce cas, le pooler de connexion proposera probablement à l'administrateur de jeter un coup d'œil à la situation. |
|
|
4.6. |
J'ai migré mon Slony-I™ en version 1.2. J'ai maintenant cet avertissement dans les journaux applicatifs : NOTICE: Slony-I: log switch to sl_log_2 still in progress - sl_log_1 not truncated Les tables sl_log_1 et sl_log_2 continuent de prendre du volume, et sl_log_1 n'est jamais vidée. Quel est le souci ? |
|
Ceci est un cas symptomatique du problème précèdent, relatif à la suppression de la réplication : s'il y a des vieilles connexions établies, qui continuent à utiliser des plan d'exécutions basés sur des vieilles procédures stockées, cela provoque des écritures dans sl_log_1. La fermeture des vieilles connexions et l'ouverture de nouvelles connexions résoudra ce problème. |
|
|
À plus long terme, un élément de la liste des choses à faire pour PostgreSQL™ est l'implantation d'une vérification des dépendances, qui pourra supprimer un plan d'exécution caché lorsqu'un objet lié à ce plan est modifié. |
|
|
4.7. |
J'ai pointé un nœud abonné vers un nœud fournisseur différent, et il a cessé la réplication. |
|
Nous avons constaté que ceci arrive lorsque on réinitialise un nœud dans la configuration suivante :
L'abonnement du nœud 3 est changé pour que le nœud 1 soit son fournisseur et on exécute SLONIK DROP SET(7) / SLONIK SUBSCRIBE SET(7) sur le nœud 2 pour qu'il soit repeuplé. Malheureusement, la réplication s'arrête soudainement sur le nœud 3. Le problème vient du fait qu'il n'y a pas d'ensemble approprié de « voies d'écoute » dans la table sl_listen pour propager les évènements depuis le nœud 1 vers le nœud 3. Les événements sont transportés vers le nœud 2 et sont bloqués par l'événement SLONIK SUBSCRIBE SET(7) que le nœud 2 est en train de traiter. Le script suivant supprime les voies d'écoute qui font transiter les événements par le nœud 2 et ajoute une voie d'écoute directe entre les nœuds 1 et 3.
cluster name = oxrslive;
node 1 admin conninfo='host=32.85.68.220 dbname=oxrslive user=postgres port=5432';
node 2 admin conninfo='host=32.85.68.216 dbname=oxrslive user=postgres port=5432';
node 3 admin conninfo='host=32.85.68.244 dbname=oxrslive user=postgres port=5432';
node 4 admin conninfo='host=10.28.103.132 dbname=oxrslive user=postgres port=5432';
try {
store listen (origin = 1, receiver = 3, provider = 1);
store listen (origin = 3, receiver = 1, provider = 3);
drop listen (origin = 1, receiver = 3, provider = 2);
drop listen (origin = 3, receiver = 1, provider = 2);
}
Juste après l'exécution de ce script, les événements SYNC se propagent à nouveau vers le nœud 3. Ceci souligne deux principes :
Les problèmes relatifs aux « voies d'écoute » sont discutés avec plus de précisions dans la section Section 9, « Voix d'écoute ». |
|
|
4.8. |
En redémarrant slon(1), j'obtiens les messages « FATAL » suivants dans les journaux applicatifs. Que se passe-t-il ? 2006-03-29 16:01:34 UTC CONFIG main: slon version 1.2.0 starting up 2006-03-29 16:01:34 UTC DEBUG2 slon: watchdog process started 2006-03-29 16:01:34 UTC DEBUG2 slon: watchdog ready - pid = 28326 2006-03-29 16:01:34 UTC DEBUG2 slon: worker process created - pid = 28327 2006-03-29 16:01:34 UTC CONFIG main: local node id = 1 2006-03-29 16:01:34 UTC DEBUG2 main: main process started 2006-03-29 16:01:34 UTC CONFIG main: launching sched_start_mainloop 2006-03-29 16:01:34 UTC CONFIG main: loading current cluster configuration 2006-03-29 16:01:34 UTC CONFIG storeSet: set_id=1 set_origin=1 set_comment='test set' 2006-03-29 16:01:34 UTC DEBUG2 sched_wakeup_node(): no_id=1 (0 threads + worker signaled) 2006-03-29 16:01:34 UTC DEBUG2 main: last local event sequence = 7 2006-03-29 16:01:34 UTC CONFIG main: configuration complete - starting threads 2006-03-29 16:01:34 UTC DEBUG1 localListenThread: thread starts 2006-03-29 16:01:34 UTC FATAL localListenThread: "select "_test1538".cleanupNodelock(); insert into "_test1538".sl_nodelock values ( 1, 0, "pg_catalog".pg_backend_pid()); " - ERROR: duplicate key violates unique constraint "sl_nodelock-pkey" 2006-03-29 16:01:34 UTC FATAL Do you already have a slon running against this node? 2006-03-29 16:01:34 UTC FATAL Or perhaps a residual idle backend connection from a dead slon? |
|
La table sl_nodelock est utilisée comme un « verrou partagé » pour empêcher que deux processus slon(1) essaient de prendre le controle du même nœud en même temps. Le slon(1) essaie d'insérer un enregistrement dans la table ; il ne peut réussir que s'il est le seul à gérer le nœud. |
|
|
Ce message d'erreur est typiquement un signe que vous avez démarrez un second processus slon(1) pour un nœud donné. Le slon(1) pose la question évidente suivante : « avez-vous déjà un slon démarré pour gérer ce nœud ? » |
|
|
En supposant que vous subissez une panne réseau, les connections entre slon(1) et la base de données peuvent échouer et slon(1) peut s'en apercevoir bien avant l'instance de PostgreSQL™ sur laquelle il est connecté. La conséquence en est qu'un certain nombre de connexions pré-établies vont rester ouvertes sur la base de données jusqu'à ce que le timeout TCP/IP arrive à échéance, chose qui normalement arrive au bout de deux heures. Durant cette période de deux heures, le slon(1) va essayer de se reconnecter, encore et encore, et fait que vous obtenez le message d'erreur ci-dessous, encore et encore. Un administrateur peut mettre fin à cette situation en se connectant sur le serveur et en lançant kill -2 pour terminer les connexions bloquantes. Malheureusement, puisque le problème a eu lieu au niveau de la couche réseau, PostgreSQL™ et Slony-I™ n'ont aucun moyen direct de détecter ceci. Vous pouvez éviter ceci dans la plupart des cas en vous assurant que le processus slon(1) est hébergé à proximité des serveurs qu'il gère. Si le slon(1) est hébergé sur le même serveur que la base de donnée qu'il gère, alors toute « panne réseau » qui peut interrompre les connexions serait susceptible d'être assez sérieus pour menacer le serveur entier. |
|
|
4.9. |
|
|
Généralement, il n'y a aucun risque à arrêter un processus slon(1). Chacun d'eux est « simplement » un client de PostgreSQL™, gérant un nœud, qui déploie des threads pour gérer et recevoir des évènements depuis d'autres nœuds. Les threads des « évènements d'écoute » ne sont pas très importants ; ils ne font que vérifier de temps en temps les nœuds distants pour déterminer s'il y a des taches à faire sur le nœud local. Si vous tuez le processus slon(1) ces threads de surveillance seront fermés, ce qui aura peu ou pas du tout d'impact. Les événements produits pendant que slon(1) est arrêté seront récupérés lors de son redémarrage. Le thread de « gestion des nœuds » est un peu plus intéressant ; la plupart du temps, sur un abonné, on peut s'attendre à ce que le thread traite des événements SYNC. Si vous arrêtez le slon(1) durant un évènement, la transaction va échouer et s'annuler. Lorsque slon(1) redémarre, il reprendra l'évènement pour l'exécuter. L'unique situation où cela peut provoquer des problèmes particulièrs est lorsque l'évènement en cours est un traitement de longue durée comme un COPY_SET pour un large ensemble de réplication. L'autre chose qui pourrait poser problème est s'il est relativement distant du nœud auxquel il est connecté ; vous pouvez découvrir que les connexions de la base de données sont laissées disponibles en transaction (« idle in transaction »). Ceci peut survenir si les connexions réseaux sont supprimées sans que ni slon(1) ni la base en aient pris connaissance. Dans ce cas, vous pouvez découvrir que des connexions « zombies » traînent encore durant deux longues heures si vous n'allez pas tuer à la main les processus PostgreSQL™. Il y existe un autre cas qui peut poser problème : quand le processus slon(1) qui administre le nœud origine ne fonctionne pas, aucun évènement SYNC ne s'exécute sur ce nœud. Si le slon(1) reste arrêté pendant une longue durée et qu'aucun processus de type Section 6.3, « En parallèle aux chiens de garde : generate_syncs.sh » n'est en cours, alors vous pouvez vous retrouver avec un énorme SYNC à effectuer lorsque le processus slon(1) du nœud origine sera relancé. Toutefois, ceci est vrai seulement si slon(1) est en arrêt pendant une période assez longue ; un arrêt de quelques secondes ne génère pas de problèmes. |
|
|
4.10. |
Y a-t-il des risques lorsqu'on arrête slon(1) ? Quels sont les avantages ? |
|
En bref, si un COPY_SET qui dure 18h n'est pas en cours d'exécution, alors ce n'est pas un grand sacrifice d'arrêter un slon(1) pendant quelques instants, ni même de relancer tous les slon(1). |
|
5. FAQ Slony-I™ : Problèmes de configuration |
|
|
5.1. |
Slonik échoue lors du chargement des bibliothèques PostgreSQL™ : PGRES_FATAL_ERROR load '$libdir/xxid'; Lorsque j'exécute un simple script de configuration, j'obtiens un message similaire à : stdin:64: PGRES_FATAL_ERROR load '$libdir/xxid'; - ERROR: LOAD: could not open file '$libdir/xxid': No such file or directory |
|
Évidemment, vous n'avez pas accès à la bibliothèque xxid.so dans le répertoire $libdir que l'instance PostgreSQL™ utilise. Notez que les composants Slony-I™ doivent être installés avec le noyau PostgreSQL™ sur chacun des nœuds et pas seulement sur le nœud d'origine. Cela peut également venir du fait d'une disparité entre les binaires du noyau PostgreSQL™ et celui du noyau de Slony-I™. Si vous avez manuellement compilé Slony-I™ par vous-même, sur une machine où il y a plusieurs versions de PostgreSQL™, il est possible que les binaires slon ou slonik demande de charger une bibliothèque qui n'est pas accessible dans les répertoires des bibliothèques de la version de PostgreSQL™ utilisée. En deux mots : ceci indique que vous devez « auditer » l'installation des instances PostgreSQL™ et Slony-I™ qui sont en place sur la machine. Malheureusement, n'importe quelle incompatibilité peut faire remonter ce genre d'erreur. Voir aussi la sécurité des threads à propos de la gestion des threads sur Solaris. La situation est plus simple si vous avez une seule version de PostgreSQL™ installée par serveur ; dans ce cas, il n'y aura pas d'« incompatibilité de chemins » là où les composants de Slony-I™ sont installés. Si vous avez une installation multiple, vous devrez vous assurer que la bonne version de Slony-I™ est associée à la bonne version du noyau de PostgreSQL™. |
|
|
5.2. |
J'essaie de créer un cluster dont le nom contient un tiret. Cela ne fonctionne pas. |
|
Slony-I™ utilise les mêmes règles de nommage que PostgreSQL™, donc vous ne devriez pas utiliser un tiret dans les identifiants. Vous pouvez tenter de mettre des simples « guillemets » pour l'identifiant, mais vous allez vous exposer à des soucis qui pourront surgir à tout moment. |
|
|
5.3. |
La commande ps affiche le mot de passe en clair. Avec la commande ps, tout le monde peut voir le mot de passe qui a été fourni sur la ligne de commande. |
|
Conservez le mot de passe en dehors de la configuration Slony, en les mettant dans le fichier $(HOME)/.pgpass.. |
|
|
5.4. |
Les index dont le nom contient le namespace
set add table (set id = 1, origin = 1, id = 27,
full qualified name = 'nspace.ma_table',
key = 'clef_sur_une_colonne',
comment = 'une table ma_table dans le namespace nspace avec une clef primaire');
|
|
Si vous avez key = 'nspace.clef_sur_une_colonne', la requête échouera. |
|
|
5.5. |
La réplication est retardée, et il semble que les requêtes sur les tables sl_log_1/sl_log_2 prennent beaucoup de temps alors qu'il n'y a que quelques événements SYNC. |
|
Jusqu'à la version 1.1.1, les tables sl_log_1/sl_log_2 possédaient seulement un index, et lorsqu'il y avait plusieurs ensembles de réplication, quelques colonnes dans l'index n'étaient pas assez discriminantes. Si l'index ne contient pas la colonne log_xid, il est conseillé de l'ajouter. Voir le script slony1_base.sql pour regarder la manière de créer cet index. |
|
|
5.6. |
J'ai besoin de renommer une colonne qui figure dans la clef primaire pour l'une de mes tables répliquées. L'opération est un peu dangereuse, n'est-ce pas ? Je dois retirer la table de la réplication puis la replacer, c'est bien ça ? |
|
En fait, cette opération fonctionne proprement. Slony-I™ fait un usage intensif des clefs primaires mais, en pratique, ce type d'opération peut se faire de manière transparente. Supposons que vous souhaitez renommer une colonne, avec la commande DDL suivante ALTER TABLE accounts ALTER COLUMN aid RENAME TO cid;. Ceci permet de renommer la colonne dans la table ; elle permet de mettre à jour simultanément l'index de la clef primaire. Le résultat est que ce genre de changement s'effectue simultanément sur un nœud donné. Dans l'ideal et pour bien faire les choses, il aurait fallu utiliser SLONIK EXECUTE SCRIPT(7) pour déployer la modification au bon moment sur chaque nœud. Toutefois, ce n'est pas forcément nécessaire. Tant que la modification est appliquée sur le nœud origine avant d'être effectuée sur les abonnés, il n'y aura pas de cassure irrémédiable. Certains évènements SYNC qui n'incluent pas la table sur laquelle il y a la modification, pourront fonctionner sans problème... Par contre, lorsqu'une mise à jour de la table est effectuée sur un abonné, alors les événements SYNC vont échouer puisque le fournisseur indiquera une « nouvelle » colonne alors que l'abonné connait toujours les « anciennes ». Dès que l'on appliquera la modification de la clef chez l'abonné, les événements SYNC seront traités de nouveau et le « nouveau » nom de colonne sera présent. Tout fonctionnera sans problème. |
|
|
5.7. |
J'ai un PostgreSQL™ version 7.2 et je souhaite vraiment utiliser Slony-I™ pour le migrer en version 8.0. Que faut-il faire pour que Slony-I™ fonctionne ? |
|
Voici Rod Taylor écrit sur le sujet... Voici approximativement ce dont vous avez besoin :
Bien sûr, une fois ces pre-requis terminés, on n'est pas encore compatible avec le Slony standard. Ainsi soit vous devez au moins modifier la version 7.2 de manière moins artisanale soit vous devez modifier slony pour qu'il fonctionne sans les schémas avec les nouvelles versions de PostgreSQL™ afin qu'ils puissent dialoguer. Juste après le déroulement de la procédure de migration de 7.2 vers 7.4, on peut désinstaller la version bidouillée de Slony (à la main encore pour la majeure partie), et démarrer la migration de 7.2 à 7.4 sur les différentes machines en utilisant un Slony standard. Ceci afin de s'assurer qu'on ne conserve pas les catalogues systèmes qui ont subi des changements manuels. Ceci étant dit, nous avons migré quelques centaines de Go de données, de 7.2 à 7.4 avec une coupure de service de 30 minutes (contre 48 heures de sauvegarde/restauration) et sans pertes de données. |
|
|
Ceci vous dresse un éventail assez laid des « bidouilles » qu'il faut faire entrer dans le périmètre de production. Si quelqu'un est intéressé pour « industrialiser » cette tache, il vaut mieux s'appuyer sur Slony-I™ en version 1.0, avec un maître mot de ne pas essayer de le rendre pérenne, étant donnée sa durée de vie limitée. Vous devriez seulement adapter cette solution que si vous êtes à l'aise avec PostgreSQL™ et Slony-I™ et si mettre la main dans le code ne vous fait pas peur. |
|
|
5.8. |
J'ai subit une « avarie réseau » qui m'a obligé à utiliser SLONIK FAILOVER(7) pour basculer sur un nœud secondaire. Le plantage n'était pas causé par un problème de corruption de données venant du disque. Pourquoi serais-je obligé de reconstruire le nœud qui s'est arrêté brutalement ? |
|
Le rôle de SLONIK FAILOVER(7) est d'abandonner le nœud arrêté brutalement et, par conséquence il n'a plus de charge générée par l'activité de Slony-I™. Plus le temps passe plus, le serveur arrêté brutalement se désynchronise. |
|
|
L'énorme problème pour restaurer le serveur planté est qu'il peut contenir des mises à jours qui n'ont pas eu le temps de se propager en dehors. Vous ne pouvez pas non plus les rejouer car elles vont être conflictuelles, car à moitié en place. En tout cas, vous avez une sorte de corruption « logique » de données, qui n'est jamais causée par une erreur disque dite « physique ». |
|
|
Comme cela a été abordé dans la section Section 8, « Effectuer une bascule d'urgence avec Slony-I », SLONIK FAILOVER(7) doit être utilisé en dernier recourt car cela implique d'abandonner le nœud d'origine pour cette corruption. |
|
|
5.9. |
Après notification d'un abonnement sur un autre nœud, la réplication échoue sur l'un des abonnés avec le message d'erreur suivant :
ERROR remoteWorkerThread_1: "begin transaction; set transaction isolation level serializable; lock table "_livesystem".sl_config_lock; select "_livesystem".enableSubscription(25506, 1, 501); notify "_livesystem_Event"; notify "_livesystem_Confirm"; insert into "_livesystem".sl_event (ev_origin, ev_seqno, ev_timestamp, ev_minxid, ev_maxxid, ev_xip, ev_type , ev_data1, ev_data2, ev_data3, ev_data4 ) values ('1', '4896546', '2005-01-23 16:08:55.037395', '1745281261', '1745281262', '', 'ENABLE_SUBSCRIPTION', '25506', '1', '501', 't'); insert into "_livesystem".sl_confirm (con_origin, con_received, con_seqno, con_timestamp) values (1, 4, '4896546', CURRENT_TIMESTAMP); commit transaction;" PGRES_FATAL_ERROR ERROR: insert or update on table "sl_subscribe" violates foreign key constraint "sl_subscribe-sl_path-ref"
DETAIL: Key (sub_provider,sub_receiver)=(1,501) is not present in table "sl_path".
Par la suite, l'erreur est suivie par un ensemble de SYNC en échec tandis que slon(1) s'arrête : DEBUG2 remoteListenThread_1: queue event 1,4897517 SYNC DEBUG2 remoteListenThread_1: queue event 1,4897518 SYNC DEBUG2 remoteListenThread_1: queue event 1,4897519 SYNC DEBUG2 remoteListenThread_1: queue event 1,4897520 SYNC DEBUG2 remoteWorker_event: ignore new events due to shutdown DEBUG2 remoteListenThread_1: queue event 1,4897521 SYNC DEBUG2 remoteWorker_event: ignore new events due to shutdown DEBUG2 remoteListenThread_1: queue event 1,4897522 SYNC DEBUG2 remoteWorker_event: ignore new events due to shutdown DEBUG2 remoteListenThread_1: queue event 1,4897523 SYNC |
|
Si vous constatez qu'un slon(1) s'arrête et que le jounal des traces indique que des événements ont été ignorés, vous devez remonter dans le journal avant que ces erreurs n'apparaissent, pour trouver des indications sur l'origine du problème. |
|
|
Dans ce cas particulier, l'erreur est due à la commande SLONIK STORE PATH(7) qui n'est pas encore répercutée sur le nœud 4 en attendant la propagation de la commande SLONIK SUBSCRIBE SET(7). Cet exemple démontre à nouveau qu'il ne faut pas se précipiter ; vous devez vous assurer que tout fonctionne correctement avant de poursuivre les changements de configuration. |
|
|
5.10. |
J'ai juste utilisé SLONIK MOVE SET(7) afin de déporter le nœud d'origine sur un nouveau serveur. Malheureusement, certains abonnés sont toujours attachés à l'ancien nœud que je viens de migrer or je ne peux les mettre hors service tant qu'ils n'ont pas reçu le signalement de ce changement. Que puis-je faire ? |
|
Vous avez besoin d'utiliser SLONIK SUBSCRIBE SET(7) afin de modifier les abonnements de ces serveurs abonnés et les réorienter vers un fournisseur qui sera disponible durant la période de maintenance.
AvertissementIl ne faut pas faire SLONIK UNSUBSCRIBE SET(7) car vous seriez obligé de recharger toutes les données à partir de zéro. |
|
|
5.11. |
Après la notification d'un abonnement auprès d'un autre serveur fournisseur, la réplication tombe en panne, et affiche des messages d'erreurs du type :
ERROR remoteWorkerThread_1: "begin transaction; set transaction isolation level serializable; lock table "_livesystem".sl_config_lock; select "_livesystem".enableSubscription(25506, 1, 501); notify "_livesystem_Event"; notify "_livesystem_Confirm"; insert into "_livesystem".sl_event (ev_origin, ev_seqno, ev_timestamp, ev_minxid, ev_maxxid, ev_xip, ev_type , ev_data1, ev_data2, ev_data3, ev_data4 ) values ('1', '4896546', '2005-01-23 16:08:55.037395', '1745281261', '1745281262', '', 'ENABLE_SUBSCRIPTION', '25506', '1', '501', 't'); insert into "_livesystem".sl_confirm (con_origin, con_received, con_seqno, con_timestamp) values (1, 4, '4896546', CURRENT_TIMESTAMP); commit transaction;" PGRES_FATAL_ERROR ERROR: insert or update on table "sl_subscribe" violates foreign key constraint "sl_subscribe-sl_path-ref"
DETAIL: Key (sub_provider,sub_receiver)=(1,501) is not present in table "sl_path".
Ceci est suivi plus tard par une série d'erreur de syncs tandis que le démon slon(1) s'arrête : DEBUG2 remoteListenThread_1: queue event 1,4897517 SYNC DEBUG2 remoteListenThread_1: queue event 1,4897518 SYNC DEBUG2 remoteListenThread_1: queue event 1,4897519 SYNC DEBUG2 remoteListenThread_1: queue event 1,4897520 SYNC DEBUG2 remoteWorker_event: ignore new events due to shutdown DEBUG2 remoteListenThread_1: queue event 1,4897521 SYNC DEBUG2 remoteWorker_event: ignore new events due to shutdown DEBUG2 remoteListenThread_1: queue event 1,4897522 SYNC DEBUG2 remoteWorker_event: ignore new events due to shutdown DEBUG2 remoteListenThread_1: queue event 1,4897523 SYNC |
|
Si vous constatez qu'un démon slon(1) s'arrête et que le jounal des traces indique que des événements ont été ignorés, vous devez remonter dans le journal avant que ces erreurs n'apparaissent, pour trouver des indications sur l'origine du problème. |
|
|
Dans ce cas particulier, le problème était que certaines commandes SLONIK STORE PATH(7) n'ont pas été transmises aux nœud 4 avant que la commande SLONIK SUBSCRIBE SET(7) ne soit propagée. C'est encore un exemple où il ne faut pas hâtivement modifier les choses ; vous devez être sûr que tout fonctionne bien avant de faire de nouveaux changements de configuration. |
|
|
5.12. |
Est-ce que l'ordre est important dans un ensemble de réplication ? |
|
La plupart de temps, il ne l'est pas. On pourrait imaginer qu'il faille déclarer les tables « mères » avant leur « filles » en fonction des relations de clefs étrangères qui les relient ; mais ce n'est pas nécessaire si, sur le nœud abonné, on a pris le soin de désactiver les déclencheurs. |
|
|
(Commentaires de Jan Wieck) L'ordre des identifiants des tables a une importance uniquement lors d'une opération de SLONIK LOCK SET(7) en préparation de basculement. Si l'ordre est différent de celui selon lequel les applications obtiennent des verrous, ces derniers peuvent se transformer en verrous interbloqués (« deadlock ») et par conséquent faire tomber l'application ou bien slon. |
|
|
(David Parker) J'ai renconté un autre cas où l'ordre des tables avait une importance : avec l'héritage. Si une table fille se présente avant la table mère, alors l'abonnement initial provoquera la suppression du contenu de la table, alors qu'elle aura probablement reçue des données. En effet, la logique de la commande copy_set effectue un delete, et non pas un delete only, ce qui implique que la suppression des données de la table maître provoquera la suppression de celle de la table fille. |
|
|
5.13. |
Si votre script slonik(1) ressemble à quelque chose comme celui ci-dessous, il peut tomber en erreur et ne jamais se terminer car on ne peut pas utiliser wait for event à l'intérieur d'un bloc try. Un bloc try est exécuté comme une seule et même transaction, et l'évènement pour lequel vous êtes en attente peut ne jamais avoir lieu dans le courant de la transaction.
try {
echo 'Moving set 1 to node 3';
lock set (id=1, origin=1);
echo 'Set locked';
wait for event (origin = 1, confirmed = 3);
echo 'Moving set';
move set (id=1, old origin=1, new origin=3);
echo 'Set moved - waiting for event to be confirmed by node 3';
wait for event (origin = 1, confirmed = 3);
echo 'Confirmed';
} on error {
echo 'Could not move set for cluster foo';
unlock set (id=1, origin=1);
exit -1;
}
|
|
Vous ne devez pas invoquer SLONIK WAIT FOR EVENT(7) à l'intérieur d'un bloc « try ». |
|
|
5.14. |
Slony-I: cannot add table to currently subscribed set 1 J'ai essayé de rajouter une table à un jeu d'ensemble et j'ai le message d'erreur suivant : Slony-I: cannot add table to currently subscribed set 1 |
|
Vous ne pouvez pas rajouter des tables à un ensemble pour lequel il y a des abonnées. Le contournement est de créer un AUTRE ensemble de réplication, d'y rajouter les tables souhaitées, de brancher les serveurs abonnés à l'ensemble de réplication 1 sur le nouveau qu'on vient de créer, et enfin de fusionner les deux ensembles. |
|
|
5.15. |
ERROR: duplicate key violates unique constraint "sl_table-pkey" En essayant de monter un deuxième ensemble de réplication, j'ai ce message : stdin:9: Could not create subscription set 2 for oxrslive! stdin:11: PGRES_FATAL_ERROR select "_oxrslive".setAddTable(2, 1, 'public.replic_test', 'replic_test__Slony-I_oxrslive_rowID_key', 'Table public.replic_test without primary key'); - ERROR: duplicate key violates unique constraint "sl_table-pkey" CONTEXT: PL/pgSQL function "setaddtable_int" line 71 at SQL statement |
|
Les identifiants des tables utilisées dans SLONIK SET ADD TABLE(7) doivent être uniques À TRAVERS TOUS LES ENSEMBLES DE REPLICATION. En conséquence, vous ne pouvez pas reprendre la numérotation à zéro à l'intérieur d'un deuxième ensemble de réplication ; si vous les numérotez de manière consécutive, le prochain ensemble de réplication doit commencer avec un identifiant supérieur à ceux de l'ensemble précédent. |
|
|
5.16. |
L'un de mes nœudss est tombé (slon(1) ou le postmaster était arrêté) et personne ne s'en est aperçu pendant plusieurs jours. Maintenant, lorsque slon(1) démarre sur ce nœud, il tourne durant cinq minutes, puis s'arrête avec l'erreur suivante : ERROR: remoteListenThread_%d: timeout for event selection Quel est le problème ? Que faire pour le résoudre ? |
|
Le problème est que le port d'écoute de ce processus (dans src/slon/remote_listener.c) arrive à une expiration de temps lorsqu'il tente de déterminer quel le prochain évènement à reprendre sur ce nœud. Par défaut, le délai d'expiration de cette interrogation est de cinq minutes ; si la reprise contient les évènements pour une durée de plusieurs jours, cela prendra beaucoup plus de temps. |
|
|
La réponse à cette question, pour les versions de Slony-I™ antérieures aux versions 1.1.7, 1.2.7, et à 1.3, serait d'augmenter le délai d'expiration dans src/slon/remote_listener.c, de recompiler slon(1) et enfin de ré-essayer. |
|
|
Une autre réponse serait de conseiller de reconstruire entièrement le nœud ayant échoué, à l'aide de la commande slonik(1) SLONIK DROP NODE(7) en le supprimant d'abord et en le recréant après. Si les mises à jours sont volumineuses côté base de données, il vaut mieux reconstruire plutôt que d'essayer de rattraper. |
|
|
Dans les version récentes de Slony-I™, il existe un nouveau paramètre appelé slon_conf_remote_listen_timeout qui permet de modifier le délai d'expiration et de relancer les mises à jour. Bien sûr, comme cela a été mentionné ci-dessus, il est plus efficace dans ce cas de supprimer et de recréer le nœud, que d'essayer de rattraper les mises à jours. |
|
|
5.17. |
À partir de la version 8.3, PostgreSQL™ propose le paramètre synchronous_commit qui peut être configuré dans la session et dans le fichier postgresql.conf. Elle permet de gagner en performance en diluant les écritures dans les journaux de transactions. Serait-il intéressant de désactiver ce paramètre sur un nœud abonné ? |
|
Malheureusement, le risque introduit est assez désagréable. En voici un exemple...
Deux possibilités, une correcte, une très mauvaise....
Ce cas est assez facile à tester, vous devez simplement empêcher le redémarrage du nœud pendant suffisament longtemps pour que le nœud 1 ait le temps de lancer le processus de nettoyage. Vous pouvez éviter le problème en configurant le paramètre slon_config_cleanup_interval avec une valeur très grande. Malheureusement, chaque fois que le nœud 2 est indisponible pendant plus de temps que cet interval, vous risquez inexorablement de perdre des données. |
|
|
Du coup, il n'est pas recommandé que les utilisateurs exécutent Slony-I™ avec synchronous_commit activé. |
|
6. FAQ Slony-I™ : problèmes de performances |
|
|
6.1. |
La réplication ralentit. Je vois des requêtes FETCH 100 FROM LOG très longues, la table sl_log_1/sl_log_2 grossit et les performances se dégradent de manière continue. |
|
Il y a beaucoup de causes possibles pour ce genre de choses. Il s'agit du même genre de pathologies qui entrainent l'augmentation du volume dans pg_listener lorsque la purge via vacuum n'est pas exécutée. Par rapprochement, « on peut avancer » que cette augmentation de volume est due à une session existante sur le serveur qui est en IDLE IN TRANSACTION pour une durée très longue. Cette transaction ouverte peut avoir de multiples effets négatifs, chacun entrainant une dégradation de performances.
|
|
|
Vous pouvez surveiller cette situation uniquement si, dans le fichier de configuration de PostgreSQL™ postgresql.conf, le paramètre stats_command_string est positionné à vrai. Dans ce cas, vous pouvez lancer une interrogation SQL comme suit : SELECT * FROM pg_stat_activity WHERE current_query LIKE '%IDLE% in transaction'; dont le résultat vous donne les transactions en activités. |
|
|
Vous pouvez également rechercher les « idle in transaction » dans la table des processus pour trouver ceux qui détiennent encore des transactions anciennes. |
|
|
Il est aussi possible (quoique plus rare) que le problème soit causé par une transaction qui, pour d'autres raisons, est conservée comme ouverte et ceci pour une longue durée. La valeur query_start dans la table pg_stat_activity vous présentera les longues requêtes qui s'exécutent depuis longtemps. |
|
|
Il est prévu que PostgreSQL™ ait un paramètre d'expiration de délai, open_idle_transaction_timeout, qui permettrait de venir à bout des transactions après une certaine période. Les pools de connexions peuvent engendrer ce genre de situation d'erreurs. Il est prévu des amélioration où pgpool™ devrait présenter des meilleures alternatives afin de mieux gérer les connexions partagées. Il existe des pools de connexions plus ou moins bogués dans les applications Java ou PHP ;si un nombre restreint de vraies connexions sont conservées dans pgpool™, ceci va faire croire à la base qu'en réalité les connexions de l'application restent dans un statut disponible et en activité pendant des heures. |
|
|
6.2. |
Après une suppression de nœud, les tables sl_log_1/sl_log_2 ne sont plus purgées. |
|
Ceci est un scénario commun dans les versions d'avant 1.0.5. En effet, le « nettoyage » du nœud oublie les vieilles entrées de la table sl_confirm pour le serveur qui vient de disparaître. Le nœud n'est plus présent et n'envoie plus les confirmations annonçant les synchronisations qui viennent de s'effectuer sur ce serveur, et le processus de nettoyage estime qu'il ne peut supprimer sans risque les entrées plus récentes que la dernière entrée de la sl_confirm , ce qui limite nettement la capacité de purge des anciens journaux. Diagnostiques : Exécuter les requêtes suivantes pour voir s'il y a un résidus d'entrées en état « fantôme/obsolète/bloqué » dans la table sl_confirm:
oxrsbar=# SELECT * FROM _oxrsbar.sl_confirm
oxrsbar-# WHERE con_origin NOT IN (SELECT no_id FROM _oxrsbar.sl_node)
oxrsbar-# OR con_received NOT IN (SELECT no_id FROM _oxrsbar.sl_node);
con_origin | con_received | con_seqno | con_timestamp
------------+--------------+-----------+----------------------------
4 | 501 | 83999 | 2004-11-09 19:57:08.195969
1 | 2 | 3345790 | 2004-11-14 10:33:43.850265
2 | 501 | 102718 | 2004-11-14 10:33:47.702086
501 | 2 | 6577 | 2004-11-14 10:34:45.717003
4 | 5 | 83999 | 2004-11-14 21:11:11.111686
4 | 3 | 83999 | 2004-11-24 16:32:39.020194
(6 rows)
Dans la version 1.0.5, la fonction SLONIK DROP NODE(7) purge les données dans sl_confirm pour le nœud qui quitte la configuration. Dans les versions plus anciennes, il faut faire cela à la main. Supposons que l'identifiant du nœud soit 3, alors la requête serait la suivante : DELETE FROM _namespace.sl_confirm WHERE con_origin = 3 OR con_received = 3; Sinon, pour chasser « tous les fantômes », vous pouvez utiliser : oxrsbar=# DELETE FROM _oxrsbar.sl_confirm oxrsbar-# WHERE con_origin NOT IN (SELECT no_id FROM _oxrsbar.sl_node) oxrsbar-# OR con_received NOT IN (SELECT no_id FROM _oxrsbar.sl_node); DELETE 6 Une « raisonnable diligence » dicterait de commencer par BEGIN et vérifier le contenu des SYNC dans la table sl_confirm avant de les purger, puis de valider l'opération par un COMMIT. Si vous supprimez par erreur les données d'un autre nœud, votre journée est perdue le temps de rattraper l'erreur commise. Vous aurez besoin d'exécuter cette opération sur chaque nœud qui reste... À noter qu'à partir de la version 1.0.5, ce n'est plus un problème car il purge les entrées inutiles de sl_confirm à deux instants : |
|
|
6.3. |
Le démon slon était éteint ce week-end. Désormais, il lui faut énormément de temps pour exécuter un sync. |
|
Jetez un coup d'œil sur les tables sl_log_1/sl_log_2 pour voir brièvement s'il y a une énorme transaction en cours d'exécution. Jusqu'à la version 1.0.2, il faut qu'il y ait un slon(1) connecté au nœud origine pour que les événements SYNC soient générés.
NoteÀ partir de la version 1.0.2, la fonction generate_sync_event() fournit une alternative à la sauvegarde... Si aucun évènement n'est généré, alors toute les mises à jour jusqu'au prochain évènement seront aggrégées dans une énorme transaction Slony-I™. Conclusion : même s'il n'y a pas d'abonné dans votre réplication, vous devez vraiment mettre en place un démon slon pour qu'il se connecte au nœud origine. Slony-I™ 1.1 fournit une procédure stockée qui permet aux SYNC d'être mis à jour par le planificateur cron même si slon(1) ne tourne pas en tâche de fond. |
|
|
6.4. |
Quelques nœuds commencent à se ralentir constamment. J'avais lancé, depuis un moment, Slony-I™ sur un nœud, et je vois que la machine est à genoux. Je vois des instructions en cours comme : FETCH 100 FROM LOG; |
|
Typiquement, ceci peut se produire lorsque pg_listener (la table qui contient les données de NOTIFY) est remplie de lignes mortes. Ce qui fait que les évènements NOTIFY prennent du temps, et causent le ralentissement de plus en plus fort du nœud affecté. Vous avez probablement besoin d'effectuer un VACUUM FULL sur pg_listener pour le nettoyer vigoureusement, puis d'effectuer un VACUUM simple sur pg_listener vraiment fréquemment. Une planification tous les cinq minutes fera l'affaire. Les démons Slon font déjà un VACUUM sur beaucoup de tables et cleanup_thread.c contient une liste de tables à nettoyer fréquemment de manière automatique. Dans Slony-I™ 1.0.2, pg_listener n'est pas inclus. Dans la version 1.0.5 et supérieure, il est purgé régulièrement. Du coup, ce problème n'a plus lieu d'être. Dans la version 1.2, pg_listener est seulement utilisé quand le nœud reçoit périodiquement l'évènement, ce qui signifie que ce problème la plupart du temps disparaît même en présence de transactions longues et lentes... Il y a, cependant, toujours un scénario où ceci peut « surgir ». Pour respecter le MVCC, les VACUUM ne peuvent pas supprimer des lignes qui sont rendues « obsolètes » à n'importe quel moment après le démarrage de la transaction la plus ancienne qui reste encore ouverte. Les transactions longues devront être évitées, car elles sont sources de soucis, même sur les nœuds abonnés. |
|
|
6.5. |
J'ai soumis une requête SLONIK MOVE SET(7) / SLONIK EXECUTE SCRIPT(7), et elle semble être coincée sur mon serveur. Les journaux de Slony-I™ ne montrent aucun avertissement et aucune erreur. |
|
Peut-être que pg_autovacuum est en cours d'exécution, et qu'il a posé des verrous sur des tables dans l'ensemble de réplication ? Ceci entraine de manière silencieuse le blocage de Slony-I™ en l'empêchant d'effectuer les opérations qui exigent l'acquisition des verrous exclusifs. Vous pourriez vérifier la présence de ce genre de verrous à l'aide de cette requête : SELECT l.*, c.relname FROM pg_locks l, pg_class c WHERE c.oid = l.relation; Un verrou ShareUpdateExclusiveLock peut bloquer les opérations de Slony-I™ qui nécessitent leurs propres verrous exclusifs, et les mettre en attente et marquées comme non-validées. |
|
|
6.6. |
Je remarque que, dans les journaux, un démon slon(1) change d'état fréquemment : « LISTEN - switch from polling mode to use LISTEN » et « UNLISTEN - switch into polling mode ». |
|
Les seuils pour commuter entre ces modes sont commandés par les paramètres de configuration slon_conf_sync_interval et slon_conf_sync_interval_timeout ; si la valeur du temps d'expiration (par défaut étant à 10000, impliquant 10s) est maintenu bas, cela encourage le démon slon(1) à retourner dans l'état « d'écoute ». Vous devriez augmenter cette valeur d'expiration de temps. |
|
7. FAQ Slony-I™ : Bugs dans les versions anciennes |
|
|
7.1. |
Les processus slon(1) gérant mes abonnés deviennent énormes, mettant en danger la ressource du système en terme de swap ainsi que le risque d'atteindre la taille limite de 2 Go par processus. D'ailleurs, les données que je suis en train de répliquer ont une taille assez grande. Il y a des enregistrements dont la taille dépasse des dizaine de mégaoctets. Peut-être que c'est lié ? |
|
Oui, ces enregistrements volumineux sont à la racine du problème. Le problème vient du fait que slon(1) procède normalement par paquet de cent enregistrements à la fois, lorsqu'un abonné charge des données depuis le fournisseur. Ainsi, si la taille moyenne des enregistrements est de 10 Mo, cela entraîne des paquets de données atteignant 1000 Mo qui sont ensuite transformés en INSERT ou en UPDATE dans la mémoire du processus slon(1). Cela mène évidemment slon(1) à des tailles gigantesques. Le nombre d'enregistrements regroupés est contrôlé par la valeur SLON_DTA_FETCH_SIZE, définie dans le fichier src/slon/slon.h. Voici un extrait de ce fichier contenant ce paramètre : #ifdef SLON_CHECK_CMDTUPLES #define SLON_COMMANDS_PER_LINE 1 #define SLON_DATA_FETCH_SIZE 100 #define SLON_WORKLINES_PER_HELPER (SLON_DATA_FETCH_SIZE * 4) #else #define SLON_COMMANDS_PER_LINE 10 #define SLON_DATA_FETCH_SIZE 10 #define SLON_WORKLINES_PER_HELPER (SLON_DATA_FETCH_SIZE * 50) #endif Si vous rencontrez ce problème, vous devriez définir SLON_DATA_FETCH_SIZE, peut-être le réduire par un facteur de 10, et recompiler ensuite slon(1). L'activation de SLON_CHECK_CMDTUPLES permet de faire une surveillance supplémentaire pour s'assurer que les abonnés ne sont pas désynchronisés par rapport au fournisseur. Par défaut, cette option est désactivée, donc la modification par défaut consiste réduire la seconde définition de SLON_DATA_FETCH_SIZE en remplaçant 10 par 1. |
|
|
Dans la version 1.2, la configuration des valeurs de sync_max_rowsize et de sync_max_largemem est associée avec un nouvel algorithme qui change la logique des choses. Plutôt que de restituer cent enregistrements à la fois :
Ceci devrait alléger des problèmes que les gens avaient éprouvé, quand ils ont chargés sporadiquement des séries de lignes très volumineuses. |
|
|
7.2. |
Je suis en train de répliquer les données de type UNICODE depuis la version 8.0 de PostgreSQL™ à la version 8.1, et je rencontre des problèmes. |
|
PostgreSQL™ 8.1 est un peu plus strict dans l'usage des codes caractères UTF-8 et Unicode, comparé à la version 8.0. Si vous êtes amené à utiliser Slony-I™ pour migrer depuis une plus vieille version vers la version 8.1 et que vous avez des valeurs UTF-8 invalides, vous aurez une surprise déplaisante. Supposons que votre version de base est la version 8.0, avec l'encodage en UTF-8. La base va accepter des séquences '\060\242' comme une valeur UTF-8 conforme, même si ce n'est pas le cas. Si vous répliquez ceci dans des instances de PostgreSQL™ en version 8.1, il va se plaindre, soit lors de l'enregistrement d'un abonné car Slony-I™ va râler à propos des codes caractères invalides qu'il vient de rencontrer durant la COPY des données, ce qui empêchera que l'enregistrement se fasse, soit lors de l'ajout de données, plus tard, ce qui brisera irrémédiablement la réplication. (Vous pouvez tricher sur le contenu de sl_log_1, mais rapidement cela deviendra vraiment intéressant...) Il y a déjà eu des discussions sur ce sujet pour savoir ce qu'il faudra faire. Pour le moment, une stratégie attractive ne se dégage pas sur le sujet. Si vous utilisez Unicode avec la version 8.0 de PostgreSQL™, vous courrez un risque considérable de corrompre vos données. Si votre réplication a pour but de convertir une fois pour toutes vos données, il y a le risque évoqué ci-dessus ; si cela vous arrive, il vaudra mieux convertir vos données de la version 8.0 d'abord et de re-essayer après. Au regard des risques encourus, exécuter la réplication en mettant en jeu des versions différentes semble être non pérenne à maintenir. Pour plus d'information, voir la discussion sur le groupe de discussion postgresql-hackers. |
|
|
7.3. |
J'utilise Slony-I™ 1.1 avec plus de 4 nœuds et deux ensembles de réplication, 1 et 2, qui ne partagent aucun nœuds. Je découvre que les confirmations pour l'ensemble 1 n'arrivent jamais aux nœuds souscrivant à l'ensemble 2, et inversement (celles de l'ensemble 2 n'arrivent pas non plus aux nœuds souscrivant à l'ensemble 1). En conséquence, sl_log_1/sl_log_2 grossissent et ne sont jamais purgées. Ceci est mentionné dans le bug 1485. |
|
Apparemment, le code de la fonction RebuildListenEntries() ne suffit pas pour résoudre ce cas. La fonction RebuildListenEntries() sera rectifié dans Slony-I™ version 1.2 avec un algorithme couvrant ce cas. Dans l'intérim, vous devrez ajouter manuellement quelques entrées dans sl_listen en utilisant SLONIK STORE LISTEN(7) ou storeListen(), basé sur les principes décrits dans Section 9, « Voix d'écoute » (apparemment pas aussi désuet que nous avons pensé). |
|
|
7.4. |
Je trouve que quelques colonnes de multibyte (Unicode, Big5) sont tronqués un peu, il leur manque les derniers caractères. Pourquoi ? |
|
C'était un bug présent jusqu'à la version 1.1.0 de Slony-I™ ; les colonnes étaient capturées par la fonction logtrigger(), qui coupait les derniers octets d'une colonne représentée dans un format de multibyte. que votre version de src/backend/slony1_funcs.c est bien la 1.34 ou supérieur ; le patch a été intégré dans la version CVS 1.34 de ce fichier. |
|
|
7.5. |
Le bug #1226 indique une condition d'erreur qui peut survenir si vous faites placer une réplication composée seulement de séquences. |
|
Une réponse courte consiste à dire qu'une réplication composée seulement de séquences n'est pas une bonne pratique. |
|
|
Le problème avec un ensemble de réplication contenant uniquement des séquences, ce sont les cas où les seuls abonnements actifs sont composés uniquement de séquences. Si un nœud entre dans cet état, la réplication échouera puisque la requête qui collecte les données dans sl_log_1/sl_log_2 ne trouveront aucune table et par conséquent la requête sera malformée et échouera. Si un ensemble de réplication contenant des tables ré-apparaît, tout va fonctionner correctement ; cela paraît effrayant. Ce problème devrait être résolu après Slony-I™ 1.1.0. |
|
|
7.6. |
Je dois supprimer une table d'un ensemble de réplication. |
|
Ceci peut être accompli de plusieurs manières, pas toutes également souhaitables ;-).
|
|
|
7.7. |
Je dois supprimer une séquence dans une séquence pour un ensemble de réplication. |
|
Si vous êtes en version 1.0.5 ou supérieure, il existe une commande SLONIK SET DROP SEQUENCE(7) dans Slonik vous permettant de le faire en parallèle SLONIK SET DROP TABLE(7). Si vous êtes en version 1.0.2 ou antérieure, l'opération sera un peu plus manuelle. À supposer que je veux me débarrasser des deux séquences suivante : whois_cachemgmt_seq et epp_whoi_cach_seq_. Tout d'abord, il nous faut les valeurs de seq_id :
oxrsorg=# SELECT * FROM _oxrsorg.sl_sequence WHERE seq_id IN (93,59);
seq_id | seq_reloid | seq_set | seq_comment
--------+------------+---------+-------------------------------------
93 | 107451516 | 1 | Sequence public.whois_cachemgmt_seq
59 | 107451860 | 1 | Sequence public.epp_whoi_cach_seq_
(2 rows)
Les données à supprimer pour empêcher Slony de continuer la réplication sont : DELETE FROM _oxrsorg.sl_seqlog WHERE seql_seqid IN (93, 59); DELETE FROM _oxrsorg.sl_sequence WHERE seq_id IN (93,59); Ces deux interrogations peuvent être soumises à l'ensemble des nœuds via la fonction schemadocddlscript_complete( integer, text, integer ) / SLONIK EXECUTE SCRIPT(7), éliminant la séquence partout « en même temps ». Ou bien on peut les appliquer à la main à chacun des nœuds. De la même manière que SLONIK SET DROP TABLE(7), cette fonction est implémentée dans Slony-I™ version 1.0.5 sous le nom SLONIK SET DROP SEQUENCE(7). |
|
|
7.8. |
J'ai configuré mon cluster avec pgAdminIII, avec le nom « MON-CLUSTER ». Le temps a passé et j'ai tenté d'utiliser Slonik pour effectuer un changement de configuration, et j'obtiens le messages d'erreur suivant : ERROR: syntax error at or near - |
|
Le problème est que Slony-I™ s'attend à ce que les noms de cluster soient des Identifiants SQL valides, et slonik(1) garantit cela. Malheureusement, pgAdminIII ne vérifie pas cela et autorise des noms de cluster qui provoquent des problèmes. |
|
|
Si vous êtes dans cette situation cas, il n'y a pas grand'chose que l'on puisse faire. Il peut-être possible que l'execution de la commande SQL alter namespace "_My-Bad-Clustername" rename to "_BetterClusterName"; sur chacune des bases fonctionne. Cela ne devrait pas particulièrement aggraverles choses ! D'un autre coté, à chaque fois que ce problème a été rencontré, il a fallu détruire la réplication et reconstruire le cluster. |
|
|
Dans la version 2.0.2, une fonction a été ajoutée pour vérifier la la validité du nom du cluster. Si vous tentez de définir un nom invalide, la chargement de la fonction échouera, avec un message d'erreur approprié, ce qui devrait empecher les choses d'empirer, meme si vous utiliser d'autres outils que slonik(1) pour gérer la configuration du cluster. |
|
8. FAQ Slony-I™ : problèmes devenus obsolètes |
|
|
8.1. |
slon(1) ne se remet pas en marche après un incident Après un arrêt immédiat de PostgreSQL™ (équivalent à un crash du système), dans la table pg_listener on trouve une ligne contenant relname='_${cluster_name}_Restart'. slon ne démarre pas car il considère qu'un autre processus gère le cluster sur ce nœud. Que puis-je faire ? la ligne ne peut pas être supprimée dans cette relation. Les journaux de traces indiquent qu'
. |
|
Le problème est que la table système pg_listener, utilisée par PostgreSQL™ pour gérer les notification d'évènements, contient quelques entrées pointant vers des processus qui n'existent plus. La nouvelle instance de slon(1) se connecte à la base, et elle est convaincue, à cause de la présence de ces entrées qu'un ancien slon est toujours en activité pour s'occuper de ce nœud de Slony-I™. Les « détritus » dans cette table doivent être nettoyés. Il est utile de maintenir un script manuel pour ce genre de situation : twcsds004[/opt/twcsds004/OXRS/slony-scripts]$ cat restart_org.slonik cluster name = oxrsorg ; node 1 admin conninfo = 'host=32.85.68.220 dbname=oxrsorg user=postgres port=5532'; node 2 admin conninfo = 'host=32.85.68.216 dbname=oxrsorg user=postgres port=5532'; node 3 admin conninfo = 'host=32.85.68.244 dbname=oxrsorg user=postgres port=5532'; node 4 admin conninfo = 'host=10.28.103.132 dbname=oxrsorg user=postgres port=5532'; restart node 1; restart node 2; restart node 3; restart node 4; SLONIK RESTART NODE(7) nettoie les notifications mortes pour qu'on puisse ensuite redémarrer le nœud. À partir de la version 1.0.5, le processus de démarrage de slon cherche ce genre de données obsolètes et les nettoie le cas échéant. À partir de la version 8.1 de PostgreSQL™, la fonction manipulant pg_listener ne supporte pas cet usage, alors, pour les versions de Slony-I™ postérieures à la 1.1.2 (e.g. - 1.1.5), ce risque d'« inter-blocage » est géré via une nouvelle table, et le problème disparaît de manière transparente. |
|
|
8.2. |
J'ai essayé la requête suivante qui ne fonctionne pas : sdb=# EXPLAIN SELECT query_start, current_query FROM pg_locks sdb-# JOIN pg_stat_activity ON pid = procpid sdb-# WHERE granted = true sdb-# AND transaction IN (SELECT transaction FROM pg_locks WHERE granted = false); ERROR: could not find hash function for hash operator 716373 Il semble que les fonctions xxid de Slony-I™ prétendent pouvoir faire du hachage, mais qu'elles n'y arrivent pas. Que se passe-t-il ? |
|
Slony-I™ a défini un nouveau type de données et d'opérateurs XXID afin de permettre la manipulation des identifiants de transaction qui sont employés pour grouper ensemble les mises à jour qui sont associées dans une même transaction. Ces opérateurs n'étaient pas disponible pour PostgreSQL™ version 7.3 et inférieure ; afin de rendre Slony-I™ opérationnel avec la version 7.3, des fonctions spécifiques doivent être ajoutées. L'opérateur = a été marqué comme supportant le hachage, mais pour que cela fonctionne, l'opérateur de jointure doit apparaître dans une classe d'opérateurs d'index haché. Cela n'a pas été défini ainsi et, en conséquence, les requêtes (comme celle ci-dessus) qui décident d'employer des jointures par hachage échoueront. |
|
|
Ceci n'a pas été considéré comme bugs « critiques », car Slony-I™ ne produit pas de requêtes employant des jointures de hachage. Ce problème ne devrait pas perturber la réplication. |
|
|
Les versions suivantes de Slony-I™ (par exemple : 1.0.6, 1.1) omettent l'indicateur HASHES. |
|
|
Supposons que vous souhaitiez réparer une instance existante, et vous constatez que vos propres scripts ne fonctionnent pas bien, vous pouvez suivre la démarche suivante : /* cbbrowne@[local]/dba2 slony_test1=*/ \x Expanded display is on. /* cbbrowne@[local]/dba2 slony_test1=*/ select * from pg_operator where oprname = '=' and oprnamespace = (select oid from pg_namespace where nspname = 'public'); -[ RECORD 1 ]+------------- oprname | = oprnamespace | 2200 oprowner | 1 oprkind | b oprcanhash | t oprleft | 82122344 oprright | 82122344 oprresult | 16 oprcom | 82122365 oprnegate | 82122363 oprlsortop | 82122362 oprrsortop | 82122362 oprltcmpop | 82122362 oprgtcmpop | 82122360 oprcode | "_T1".xxideq oprrest | eqsel oprjoin | eqjoinsel /* cbbrowne@[local]/dba2 slony_test1=*/ update pg_operator set oprcanhash = 'f' where oprname = '=' and oprnamespace = 2200 ; UPDATE 1 |
|
|
8.3. |
Je peux faire un pg_dump et recharger les données beaucoup plus rapidement qu'avec SUBSCRIBE SET. Comment est-ce possible ? |
|
Slony-I™ dépend de l'existance d'un index sur la clef primaire et ne touche pas aux autres index pendant l'opération PostgreSQL™ COPY qui charge les données. Par ailleurs, il peut y avoir une dégradation de performance, provoquée par l'événement COPY SET (un événement généré lors d'un abonnement) dans la mesure où l'opération commence par une suppression des contenus des tables, ce qui laisse la table remplie de lignes mortes. Lorsque vous utilisez pg_dump pour exporter le contenu de la base, et que vous les re-importez après, les index ne sont crées qu'à la fin. Il est beaucoup plus performant de reconstruire les index sur une table entièrement re-importée, plutôt que de refaire les index à la volée lorsque les enregistrements sont rajoutés un à un à la table. |
|
|
Si vous pouvez supprimer des index inutiles, lorsque COPY se met en marche, les performances sont sensiblement améliorée. Encore mieux, si vous pouvez faire un TRUNCATE sur les tables dont le contenu devra disparaître, les performances vont augmenter énormément. |
|
|
Slony-I™, en version 1.1.5 et supérieures, fait cela automatiquement ; il « dégage » les index dans le catalogue de PostgreSQL™ afin de les cacher, de la même façon qu'il cache les triggers, puis il « répare » les pointeurs d'index et effectue une reindexation de la table. |
|
|
8.4. |
La réplication échoue à cause d'une violation de contrainte unique. Alors que la réplication se déroule correctement depuis un bout de temps, un nœud rencontre un « soucis » et les erreurs suivantes sont envoyées dans le journal :
DEBUG2 remoteWorkerThread_1: syncing set 2 with 5 table(s) from provider 1
DEBUG2 remoteWorkerThread_1: syncing set 1 with 41 table(s) from provider 1
DEBUG2 remoteWorkerThread_1: syncing set 5 with 1 table(s) from provider 1
DEBUG2 remoteWorkerThread_1: syncing set 3 with 1 table(s) from provider 1
DEBUG2 remoteHelperThread_1_1: 0.135 seconds delay for first row
DEBUG2 remoteHelperThread_1_1: 0.343 seconds until close cursor
ERROR remoteWorkerThread_1: "insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '34', '35090538', 'D', '_rserv_ts=''9275244''');
delete from only public.epp_domain_host where _rserv_ts='9275244';insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '34', '35090539', 'D', '_rserv_ts=''9275245''');
delete from only public.epp_domain_host where _rserv_ts='9275245';insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '26', '35090540', 'D', '_rserv_ts=''24240590''');
delete from only public.epp_domain_contact where _rserv_ts='24240590';insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '26', '35090541', 'D', '_rserv_ts=''24240591''');
delete from only public.epp_domain_contact where _rserv_ts='24240591';insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '26', '35090542', 'D', '_rserv_ts=''24240589''');
delete from only public.epp_domain_contact where _rserv_ts='24240589';insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '11', '35090543', 'D', '_rserv_ts=''36968002''');
delete from only public.epp_domain_status where _rserv_ts='36968002';insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '11', '35090544', 'D', '_rserv_ts=''36968003''');
delete from only public.epp_domain_status where _rserv_ts='36968003';insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '24', '35090549', 'I', '(contact_id,status,reason,_rserv_ts) values (''6972897'',''64'','''',''31044208'')');
insert into public.contact_status (contact_id,status,reason,_rserv_ts) values ('6972897','64','','31044208');insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '24', '35090550', 'D', '_rserv_ts=''18139332''');
delete from only public.contact_status where _rserv_ts='18139332';insert into "_oxrsapp".sl_log_1 (log_origin, log_xid, log_tableid, log_actionseq, log_cmdtype, log_cmddata) values ('1', '919151224', '24', '35090551', 'D', '_rserv_ts=''18139333''');
delete from only public.contact_status where _rserv_ts='18139333';" ERROR: duplicate key violates unique constraint "contact_status_pkey"
- qualification was:
ERROR remoteWorkerThread_1: SYNC aborted
La transaction s'annule, et Slony-I™ essaie à nouveau sans cesse. Le problème est dû à une des dernières requêtes SQL, celle qui contenait log_cmdtype = 'I'. Ce n'est pas évident du tout ; Slony-I™ regroupe dix opérations de mise à jour ensemble, afin de diminuer les allers-retours réseau. |
|
Il est difficile de déterminer avec exactitude l'origine de tout ceci. En même temps, nous notons qu'il y a un problème : les transactions annulées ont été supprimées dans sl_log_1, et on constate qu'il est impossible de les récupérer. À ce stade, il parait nécessaire de supprimer l'ensemble de réplication (ou même le nœud), et de redémarrer la réplication à partir de zéro pour ce nœud. Dans Slony-I™ 1.0.5, l'opération de purge de sl_log_1 devient plus prudente, en refusant de purger des entrées qui n'ont pas encore été synchronisées, pendant au moins dix minutes sur l'ensemble des nœuds. Il n'est pas certain que ceci empêche que le « problème » ait lieu, mais il paraît plausible que cela laisse assez de données dans sl_log_1 permettant un recouvrement ou bien de permettre d'au moins de diagnostiquer plus exactement la situation. Et peut-être que le problème venait du fait que sl_log_1 était brutalement purgée, donc cette solution permet de résoudre complètement ce genre d'incident. C'est une honte de devoir reconstruire une réplication volumineuse sur un nœud à cause de cela. Si vous découvrez que le problème persiste, la bonne idée serait de diviser la réplication en plusieurs ensembles de réplication afin de dimininuer la charge de travail lors de la reconstruction de la réplication. Si un seul ensemble est cassé, vous n'auriez qu'à désabonner et supprimer celui-ci. Dans un cas, nous avons trouvé dans le journal de trace deux lignes identiques concernant l'insertion dans sl_log_1. Ceci devrait être impossible d'autant plus qu'il s'agit d'une clef primaire sur sl_log_1. La dernière théorie sur le sujet laisserait à penser que cette situation viendrait du fait que l'index de cette clé était peut-être corrompu (à cause d'un bug de PostgreSQL™), et qu'il serait possible d'éviter ce problème en exécutant la commande suivante : # REINDEX TABLE _slonyschema.sl_log_1; Au moins dans une occasion cette solution s'est révélée efficace, alors cela sera dommage de ne pas suivre l'exemple. |
|
|
Ce problème s'est avéré être un bug dans PostgreSQL™ plutôt qu'un bug dans Slony-I™. La version 7.4.8 a intégré deux solutions qui permettent de résoudre ce cas. Donc, si vous avez un noyau de PostgreSQL™ antérieur à 7.4.8, vous devriez migrer pour éviter l'erreur. |
|
|
8.5. |
J'ai commencé à faire une sauvegarde via pg_dump, et Slony s'arrête soudainement. |
|
Aïe. Ce qui se passe ici est un conflit entre :
La requête initiale qui est bloquée est :
SELECT "_slonyschema".createEvent('_slonyschema, 'SYNC', NULL);
(vous pouvez voir ceci dans la vue pg_stat_activity, si l'affichage des requête est activé dans postgresql.conf) La requête qui demande ce verrou vient de la fonction Slony_I_ClusterStatus(), que vous trouverez dans slony1_funcs.c, localisé dans un bloc de code qui est :
LOCK TABLE %s.sl_event;
INSERT INTO %s.sl_event (...stuff...)
SELECT currval('%s.sl_event_seq');
La demande de VERROU va donc attendre et durer jusqu'à ce que pg_dump (ou un autre programme ayant un verrou d'accès sur sl_event) se termine. Chaque lecture touchant sl_event sera bloqué derrière les appels à createEvent. Les réponses à cette question sont multiples :
|
|
9. FAQ Slony-I™ : Bizzareries et modifications dans Slony-I |
|
|
9.1. |
Que se produit-il avec les règles et les déclencheurs pour les tables répliquées par Slony-I™ ? |
|
Tout d'abord, regardons comment ceci est géré en dehors du cas spécifique de la commande Slonik SLONIK STORE TRIGGER(7). La fonction schemadocaltertableforreplication( integer ) prépare chacune des tables pour la réplication.
Un effet secondaire malheureux est que cette gestion des règles et des déclencheurs a pour effet de les « piétiner ». Les règles et les déclencheurs sont toujours là, mais ne sont plus correctement attachés à leurs tables. Si vous faites un pg_dump sur un « nœud abonné », il ne trouvera ni les règles ni les déclencheurs, et du coup il ne s'attend pas à les voir associés à un index. |
|
|
Maintenant, observez comment SLONIK STORE TRIGGER(7) entre en jeu. Pour simplifier, cette commande permet de restaurer les déclencheurs avec la fonction alterTableRestore(table id), qui restaure l'identifiant OID de la table dans la colonne tgrelid de pg_trigger ou pg_rewrite sur le nœud affecté. |
|
|
Ceci implique que le jour où vous souhaitez lancer une sauvegarde directement sur un abonné, vous devrez reprendre le schéma depuis un nœud d'origine. Clairement, il faudra faire : % pg_dump -h originnode.example.info -p 5432 --schema-only --schema=public ourdb > schema_backup.sql % pg_dump -h subscribernode.example.info -p 5432 --data-only --schema=public ourdb > data_backup.sql |
|
|
9.2. |
J'ai essayé les commandes SLONIK EXECUTE SCRIPT(7) ou SLONIK MOVE SET(7), et trouvé les messages suivants sur l'un des abonnés : NOTICE: Slony-I: multiple instances of trigger defrazzle on table frobozz NOTICE: Slony-I: multiple instances of trigger derez on table tron ERROR: Slony-I: Unable to disable triggers |
|
La difficulté semble venir du fait que vous avez ajouté des déclencheurs sur des tables dont le nom rentre en conflit, avec les déclencheurs que Slony-I™ a caché. Slony-I™ cache des déclencheurs (sauf ceux marqués comme « visibles » via SLONIK STORE TRIGGER(7)) en les attachant à la clé primaire de leur table. Dans le cas d'un déclencheur pour clef étrangère ou d'autres déclencheurs de cohérence des données, il est complètement inutile de les placer sur un abonnné. Au contraire, ces déclencheurs doivent être mis en place sur le nœud d'origine. En revanche, les déclencheurs de type « invalidation de cache » peuvent être placés sur l'abonné. La bonne manière de manipuler ce genre de déclencheurs est d'utiliser SLONIK STORE TRIGGER(7), qui indique à Slony-I™ de ne pas désactiver le déclencheur. |
|
|
Mais il peut y avoir quelques DBA intrépides qui vont assumer individuellement ce travail en installant les déclencheurs à la main sur l'abonné, et cela mène généralement à créer ce genre de situation. Que faire ? La réponse est assez simple : retirez le déclencheur « spécifique » sur l'abonné avant que slony tente de les restaurer. Dans le meilleur des cas, si le DBA est intrépide et réactif, il aurait fait cela avant que le message ait le temps d'arriver. Si le DBA n'est pas intrépide, il faut se connecter au nœud qui pose problème, et de supprimer la version « visible » du déclencheur utilisant l'ordre SQL DROP TRIGGER. Ceci permet à l'évènement de se dérouler. Si l'évènement était SLONIK EXECUTE SCRIPT(7), alors notre « pas-tellement-intrépide » DBA devra remettre en place le déclencheur à la main, ou, s'il a plus de sagesse, il les réactivera avec SLONIK STORE TRIGGER(7). |
|
|
9.3. |
Le comportement : tous les nœuds abonnés commencent à tomber et ont le message d'erreur suivant dans le journal. (lorsque j'ai rencontré ce problème, il y avait une longue requête SQL devant chaque message) ERROR remoteWorkerThread_1: helper 1 finished with error ERROR remoteWorkerThread_1: SYNC aborted |
|
La cause : vous avez probablement effectué un ALTER TABLE directement sur la base au lieu de l'utilisation de la commande slonik SLONIK EXECUTE SCRIPT(7). La solution consiste à remettre le trigger sur la table affectée, et de corriger à la main les données afférentes dans sl_log_1/sl_log_2.
|
|
|
9.4. |
Le nœud numéro 1 a été supprimé via SLONIK DROP NODE(7), et le slon(1) d'un autre nœud plante systématiquement avec le message d'erreurs suivant :
ERROR remoteWorkerThread_3: "begin transaction; set transaction isolation level
serializable; lock table "_mailermailer".sl_config_lock; select "_mailermailer"
.storeListen_int(2, 1, 3); notify "_mailermailer_Event"; notify "_mailermailer_C
onfirm"; insert into "_mailermailer".sl_event (ev_origin, ev_seqno, ev_times
tamp, ev_minxid, ev_maxxid, ev_xip, ev_type , ev_data1, ev_data2, ev_data3
) values ('3', '2215', '2005-02-18 10:30:42.529048', '3286814', '3286815', ''
, 'STORE_LISTEN', '2', '1', '3'); insert into "_mailermailer".sl_confirm
(con_origin, con_received, con_seqno, con_timestamp) values (3, 2, '2215', CU
RRENT_TIMESTAMP); commit transaction;" PGRES_FATAL_ERROR ERROR: insert or updat
e on table "sl_listen" violates foreign key constraint "sl_listen-sl_path-ref"
DETAIL: Key (li_provider,li_receiver)=(1,3) is not present in table "sl_path".
DEBUG1 syncThread: thread done
Il semble évident qu'un appel à SLONIK STORE LISTEN(7) n'avait pas encore été propagé avant que le nœud 1 soit éliminé. |
|
Ceci illustre le cas où vous avez besoin de réaliser une « opération chirurgicale » sur un ou plusieurs nœuds. Un évènement STORE_LISTEN demeure sans réponse alors qu'il veut ajouter une voie d'écoute qui ne peut pas être créé car le nœud 1 ainsi que toutes les voies vers le nœud 1 ont disparu. Supposons, pour la démonstration, que les nœuds encore en place soient le 2 et le 3, ainsi le rapport d'erreur est remonté au nœud 3. Cela implique que l'évènement soit stocké sur le nœud 2, puisqu'il ne peut pas être sur le nœud 3, vu qu'il n'a pas été traité avec succès. La manière la plus facile pour faire face à cette situation est de supprimer la ligne erronée dans sl_event sur le nœud 2. Vous vous connectez à la base du nœud 2, et vous recherchez l'évènement STORE_LISTEN : SELECT * FROM sl_event WHERE ev_type='STORE_LISTEN'; La requête peut ramener plusieurs lignes, mais ne supprimez que la partie nécessaire. -# begin; -- Don't straight delete them; open a transaction so you can respond to OOPS BEGIN; -# delete from sl_event where ev_type = 'STORE_LISTEN' and -# (ev_data1 = '1' or ev_data2 = '1' or ev_data3 = '1'); DELETE 3 -# -- Seems OK... -# commit; COMMIT La prochaine fois que le démon slon du nœud 3 va démarrer, il ne trouvera plus l'évènement STORE_LISTEN « erroné », et la réplication pourra se poursuivre. (cependant, vous pourrez ensuite voir surgir un vieil évènement enregistré qui fait référence à une configuration qui n'existe plus...) |
|
|
9.5. |
J'ai une base qui nous provoque les erreurs suivants dans notre application : permission denied for sequence sl_action_seq Lorsque nous traçons ce message, il est du à la fonction lastval() qui récupère la plus récente mise à jour de la séquence, ce qui revient à attraper la dernière mise à jour d'une séquence interne Slony-I™. |
|
Slony-I™ utilise des séquences pour attribuer les valeurs des clefs primaires des lignes de logs, On pouvait donc s'attendre à ce genre de comportement. Appeler lastval(), pour obtenir « anonymement » « la valeur de séquence la plus récemment modifiée », plutot que d'utiliser la currval('sequence_name') est une pratique risquée en général, car tout autre application qui utiliser le SGBD pour tracer l'arctivité, archiver ou répliquer peut déclencher une mise à jour de séquence au moment ou vous vous y attendez le moins. De manière générale, l'utilisation de lastval() n'est pas très sécurisante, l'utiliser lorsque Slony-I™ ( ou un système similaire de réplication basé sur les triggers comme Londiste ou Bucardo) peut vous conduire à des mises à jour de séquence inopinées. |
|