Last modified: Sun Jan 30 09:14:28 JST 2011
Bienvenue sur la page de pgpool-II


pgpool-II

pgpool-II est un middleware qui se place entre les serveurs PostgreSQL et les clients de ces derniers. Voici ses différentes fonctionalités:

  • Pooling de connexions
  • pgpool-II maintient les connexions établies aux serveurs PostgreSQL et les réutilise dès qu'une nouvelle connexion partageant les mêmes propriétés (c'est-à-dire même utilisateur, même base de données et même version de protocole) arrive. Il réduit ainsi le coût de la connexion et améliore les performances générales du système.

  • Réplication
  • pgpool-II peut gérer plusieurs serveurs PostgreSQL. En activant le mode réplication, il devient possible de créer une sauvegarde continue sur d'autres instances PostgreSQL, afin que le service puisse continuer sans interruption si l'une de ces instances était défaillante.

  • Répartition de charge
  • Si une base de données est répliquée, exécuter une requête en SELECT sur n'importe lequel de ceux-ci retournera le même résultat. pgpool-II profite ainsi avantageusement de la réplication pour réduire la charge sur chacun des serveurs PostgreSQL. Il parvient à cela en distribuant les requêtes SELECT entre tous les serveurs disponibles, ce qui qui améliore les performances générales du système. Dans un scénario idéal, les performances en lecture s'améliorent proportionnellement au nombre de serveurs PostgreSQL. La répartition de charge avec pgpool-II fonctionne au mieux dans un scénario où il y a beaucoup d'utilisateurs qui exécutent beaucoup de requêtes en lecture au même moment.

  • Limitation des connexions excédentaires
  • Dans PostgreSQL, il y a une limite maximum du nombre de connexions concurrentes au serveur (NDT: paramètre max_connections), et toutes les nouvelles connexions sont rejettées une fois que ce nombre est atteint. Augmenter ce nombre est possible mais accroît la consommation de ressources par le serveur et a un impact négatif sur les performances générales du système. Bien que pgpool-II ait aussi une limite sur le nombre de connexions maximum, il va mettre toute connexion excédentaire dans une file d'attente au lieu de retourner immédiatement une erreur.

  • Requêtes parallèlisées
  • En utilisant la fonctionalité des requêtes parallèlisées, les données peuvent être réparties sur plusieurs serveurs afin que les requêtes puissent être exécutées sur tous les serveurs à la fois, en réduisant ainsi le temps d'exécution global de la requête. Cette fonctionalité donne les meilleurs résultats lorsqu'on cherche à extraire un très grand ensemble de données.

pgpool-II utilise le même protocole que le serveur et les clients PostgreSQL, et relaie les messages entre les deux. Ainsi, une application cliente va prendre pgpool-II pour le serveur, et ce dernier va voir pgpool-II comme une application cliente. Puisque pgpool-II est complètement transparent, il peut-être utilisé pour une application sans pratiquement rien changer de son code source.

Il y a cependant quelques restrictions à l'utilisation du SQL via pgpool-II. Veuillez vous reporter à la section Restrictions pour plus de détails.

Plates-formes supportées

pgpool-II fonctionne sous Linux, Solaris, FreeBSD et la plupart des architectures UNIX. Windows n'est pas supporté. Les versions 6.4 et ultérieures de PostgreSQL sont supportées. Cependant, pour utiliser la fonctionalité de requêtage en parallèle, vous devez avoir un serveur en version 7.4 ou supérieure.

Si vous utilisez PostgreSQL en version 7.3 ou inférieure, certaines fonctionnalités de pgpool-II ne seront pas disponibles. Cependant, vous ne devriez pas utiliser une si vieille version de toute façons.

Vous devez aussi être certain que vos serveurs PostgreSQL sont tous dans la même version majeure. De plus, les architectures matérielles et logicielles (systèmes d'exploitation) doivent-être identiques si vous voulez utiliser la technologie « online recovery ».

Installation de pgpool-II

pgpool-II est téléchargeable sur la page de développement de pgpool. Plusieurs packages sont aussi fournis pour diverses plates-formes incluant CentOS, RedHat Enterprise Linux, Fedora et Debian.

Le code source de pgpool-II est téléchargeable sur la page de développement de pgpool.

Pour installer pgpool-II depuis son code source, vous aurez besoin de gcc, en version 2.9 ou supérieure, et de GNU make. pgpool-II utilisant la bibliothèque libpq de PostgreSQL, celle-ci doit aussi être installée ainsi que les fichiers d'en-tête sur la machine utilisée pour compiler pgpool-II. Si vous souhaitez activer le support d'OpenSSL dans pgpool-II, il vous faudra aussi avoir cette bibliothèque ainsi que les fichiers d'en-tête relatifs installés sur la machine de compilation.

Configuration

Après avoir extrait les sources depuis l'archive, exécutez le script de configuration comme suit.

./configure
Plusieurs options de configuration ont des valeurs par défaut, mais vous pouvez cependant les surcharger comme suit :
  • --prefix=path
    Les binaires de pgpool-II ainsi que sa documentation seront installés dans ce répertoire. La valeur par défaut est /usr/local.
  • --with-pgsql=path
    Répertoire sous lequel les bibliothèques de PostgreSQL sont installées. La valeur par défaut est fournie par l'utilitaire pg_config.
  • --with-openssl
    Avec cette option, les binaires de pgpool-II seront compilés avec le support d'OpenSSL. Par défaut, le support d'OpenSSL est désactivé.

Compilation

make
make install
Ces deux commandes suffisent pour compiler et installer pgpool-II. Si vous utilisez Solaris ou FreeBSD, remplacez make par gmake.

Installation de pgpool_regclass

Si vous utilisez PostgreSQL 8.0 ou supérieur, l'installation des fonctions pgpool_regclass, utiles à pgpool-II, est fortement recommandée. Sans celles-ci, le support de tables homonymes mais figurant dans des schémas différents pourrait ne pas fonctionner correctement (pour les tables temporaires, il n'y a aucun problème).

cd pgpool-II-x.x.x/sql/pgpool-regclass
make
make install
psql -f pgpool-regclass.sql template1

L'exécution du script pgpool-regclass.sql doit être faite sur toutes les bases qui sont accédées via pgpool-II. Vous n'avez pas besoin de le faire pour toutes les bases de données créées après l'exécution des commandes ci-dessus car la base template1 est la base utilisée comme modèle par défaut pour les nouvelles bases de données sous PostgreSQL.

Installation de pgpool_walrecrunning

Si vous utilisez PostgreSQL 9.0 ou supérieur avec le « streaming replication », vous aurez besoin d'installer la fonction pgpool_walrecrunning sur tous les serveurs PostgreSQL accedées par pgpool-II.

cd pgpool-II-x.x.x/sql/pgpool-walrecrunning
make
make install
psql -f pgpool-walrecrunning.sql template1

L'exécution du script pgpool-walrecrunning.sql doit-être faite sur toutes les bases de données accedées par pgpool-II. Comme précedemment, vous n'avez pas besoin de le faire pour toutes les bases de données créées après l'exécution des commandes ci-dessus car la base template1 est la base utilisée comme modèle par défaut pour les nouvelles bases de données sous PostgreSQL.

Configuration de pgpool-II

Les fichiers de configuration par défaut de pgpool-II sont /usr/local/etc/pgpool.conf et /usr/local/etc/pcp.conf. Plusieurs modes de fonctionnement sont disponibles sous pgpool-II. Chaque mode a des fonctionnalités associées qui peuvent être activées ou désactivées, mais aussi configurées pour contrôler leur comportement.

Fonction/Mode Raw Mode (*3) Mode réplication Mode maître/esclave Mode de requêtage en parallèle
Pooling de connexions X O O O
Réplication X O X (*1)
Répartition de charge X O O (*1)
Failover O O O X
Online recovery X 0 (*2) X
Requêtage en parallèle X X X O
Nombre de serveurs requis 1 ou plus 2 ou plus 2 ou plus 2 ou plus
Base de donnée système requise? non non non oui

  • 0 signifie 'disponible' et X 'indisponible'
  • (*1) Le mode de requêtage en parallèle nécessite que la réplication et la répartition de charge soient activés, cependant la réplication et la répartition de charge ne peuvent pas être utilisés pour les tables distribuées en mode de requêtage parallèlisé.
  • (*2) Le online recovery peut-être utilisé en mode maître/esclave avec la « Streaming Replication ».
  • (*3) Les clients se connectent simplement aux serveurs PostgreSQL via pgpool-II. Ce mode est utile pour limiter simplement les connexions excédentaires aux serveurs, ou activer le failover avec de multiples serveurs.

Configuration de pcp.conf

Une interface de contrôle est fournie avec pgpool-II et permet à l'administrateur de vérifier l'état de pgpool-II et d'arrêter les processus de pgpool-II à distance. pcp.conf est le fichier contenant la définition des utilisateurs et de leurs mots de passe pour accéder à cette interface. Tous les modes d'utilisation de pgpool-II nécessitent que le fichier pcp.conf soit renseigné. Un fichier d'exemple $prefix/etc/pcp.conf.sample est créé lors de l'installation de pgpool-II. Renommez ce fichier en pcp.conf, ajoutez-y votre nom d'utilisateur ainsi que votre mot de passe.

cp $prefix/etc/pcp.conf.sample $prefix/etc/pcp.conf

Une ligne vide ou commençant par un dièse (#) est traitée comme un commentaire et sera ignorée. Un nom d'utilisateur et son mot de passe doivent être écrits sur une seule ligne et respecter le format suivant :

nom_d_utilisateur:[mot de passe crypté en md5]

Le [mot de passe crypté en md5] peut être obtenu avec la commande $prefix/bin/pg_md5.

pg_md5 -p
password: <votre mot de passe>

ou

./pg_md5 foo
acbd18db4cc2f85cedef654fccc4a4d8

Le fichier pcp.conf doit être lisible par l'utilisateur qui exécute pgpool-II.

Configuration de pgpool.conf

Comme cela a déjà été expliqué, chaque mode de pgpool-II a ses propres paramètres de configuration dans le fichier pgpool.conf. Un fichier d'exemple $prefix/etc/pgpool.conf.sample est créé lors de l'installation de pgpool-II. Renommez ce fichier en pgpool.conf et éditez son contenu.

cp $prefix/etc/pgpool.conf.sample $prefix/etc/pgpool.conf

Toute ligne vide ou commençant par "#" sera traitée comme un commentaire et sera donc ignorée.

Paramètres communs

listen_addresses

Spécifie le nom de la machine ou son adresse IP, sur laquelle pgpool-II acceptera les connexions TCP/IP. '*' accepte toutes les connexions. '' empêchera toute connexion TCP/IP. La valeur par défaut est 'localhost'. Les connexions via les sockets UNIX sont toujours acceptées. Ce paramètre ne peut être modifié qu'au démarrage du serveur.

port

Spécifie le numéro de port sur lequel pgpool-II écoute les connexions. La valeur par défaut est 9999. Ce paramètre ne peut être modifié qu'au démarrage du serveur.

socket_dir

Répertoire dans lequel sera créé le socket UNIX de pgpool-II pour les connexions entrantes. La valeur par défaut est '/tmp'. Faites attention au fait que ce socket pourrait être effacé par une tâche programmée en cron. Aussi, nous vous recommandons de configurer cette valeur à '/var/run' ou un répertoire de ce type. Ce paramètre ne peut être modifié qu'au démarrage du serveur.

pcp_port

Numéro de port sur lequel le processus PCP accepte les connexions. La valeur par défaut est 9898. Ce paramètre ne peut être modifié qu'au démarrage du serveur.

pcp_socket_dir

Chemin du répertoire UNIX où le socket UNIX acceptant les connexions pour les commandes PCP est créé. La valeur par défaut est '/tmp'. Faites attention au fait que cet socket pourrait être effacé par une tâche programmée en cron. Aussi, nous vous recommandons de configurer cette valeur à '/var/run' ou un répertoire de ce type. Ce paramètre ne peut être modifié qu'au démarrage du serveur.

backend_socket_dir

À NE PLUS UTILISER Ce paramètre n'est présent que pour garantir la cohérence avec la politique par défaut de la bibliothèque libpq. Reportez-vous à la définition du paramètre backend_hostname pour adapter votre configuration.

Ce paramètre permettait de définir le répertoire UNIX servant au serveur PostgreSQL.

pcp_timeout

Délai maximum en secondes pour l'établissement d'une connexion PCP. Si un client ne répond plus au bout de cette valeur en secondes, le processus PCP ferme la connexion avec le client. La valeur par défaut est de 10 secondes. 0 signifie que la vérification du délai est désactivée. Ce paramètre est pris en compte lors du rechargement des fichiers de configuration.

num_init_children

Nombre de processus pré-forkés de pgpool-II. La valeur par défaut est de 32. num_init_children est aussi la limite du nombre de connexions clientes concurrentes à pgpool-II. Si plus de num_init_children clients essaient de se connecter à pgpool-II, ceux-ci sont bloqués (mais pas rejettés), jusqu'à ce qu'une connexion à l'un des processus de pgpool-II soit fermé. On peut avoir ansi jusqu'à deux fois num_init_children clients dans la queue de connexion.

Quelques précisions et astuces :

  • L'annulation d'une requête crée une autre connexion au processus serveur PostgreSQL ; ainsi, une requête ne peut pas être annulée si toutes les connexions sont utilisées. Si vous voulez vous assurer que les requêtes puissent être annulées, positionnez cette valeur au double des connexions attendues.
  • PostgreSQL permet un certain nombre de connexions pour les utilisateurs qui ne sont pas superutilisateurs. On le calcule ainsi :max_connections - superuser_reserved_connections

Pour résumer, max_pool,num_init_children, max_connections et superuser_reserved_connections doivent satisfaire la formule suivante :

  • Si on n'a pas besoin de l'annulation de requêtes :
    max_pool*num_init_children <= (max_connections - superuser_reserved_connections)
  • Si on a besoin de l'annulation de requêtes :
    max_pool*num_init_children*2 <= (max_connections - superuser_reserved_connections)
Ce paramètre ne peut être modifié qu'au démarrage du serveur.

child_life_time

Durée de vie en secondes d'un processus fils de pgpool-II. Lorsqu'un processus fils est sans activité depuis ce nombre de secondes, il se termine et un nouveau processus fils est créé. Ce paramètre est une mesure pour prévenir tout problème de mémoire et autres erreurs inattendues. La valeur par défaut est 300 (5 minutes). Cette fonctionalité est désactivée si cette option a une valeur de 0. Notez que cela ne s'applique qu'aux processus qui n'ont pas encore été utilisés ou qui n'ont pas encore accepté de connexions. Vous devez recharger le fichier de configuration pgpool.conf si vous changez cette valeur.

child_max_connections

Un processus fils de pgpool-II sera terminé après avoir accepté ce nombre de connexions clientes. Ce paramètre est utile sur un serveur à ce point chargé que ni child_life_time, ni connection_life_time ne sont déclenchés. Vous devez recharger pgpool-II si vous changez cette valeur.

client_idle_limit

Déconnecte un client s'il est resté inactif pendant ce nombre de secondes après que la dernière requête ne se soit terminée. Ceci est utile pour empêcher qu'un processus fils de pgpool-II ne soit occupé par un client inactif ou une connexion TCP/IP rompue entre le client et pgpool-II. La valeur par défaut de client_idle_limit est de 0, ce qui signifie que cette fonctionalité est désactivée. Ce paramètre est ignoré dans la seconde phase d'un online recovery. Vous aurez besoin de recharger pgpool-II si vous modifiez client_idle_limit.

authentication_timeout

Spécifie le délai maximum en secondes pour terminer une authentification. 0 désactive cette fonctionnalité. Vous aurez besoin de redémarrer pgpool-II si vous changez cette valeur.

logdir

Répertoire utilisé pour les logs. pgpool_status est écrit dans ce répertoire.

log_destination

pgpool-II utilise plusieurs méthodes pour écrire les messages du serveur. Cela inclut stderr et syslog. La valeur par défaut est d'envoyer les messages à stderr.

Note: vous aurez besoin de modifier la configuration du serveur syslog de votre système pour que l'écriture des messages vers syslog fonctionne. pgpool-II peut envoyer les traces à syslog en utilisant les niveaux LOCAL0 à LOCAL7 (voir la documentation de syslog), mais la valeur par défaut de syslog sur la plupart des plates-formes ignorera de tels messages. Vous aurez donc besoin d'ajouter quelque-chose comme

	local0.*    /var/log/pgpool.log
	

au fichier de configuration de votre démon syslog pour le faire fonctionner.

syslog_facility

Lorsque la sortie des messages vers syslog est configurée, ce paramètre détermine le niveau syslog à utiliser. Vous pouvez choisir toute valeur entre LOCAL0 et LOCAL7. La valeur par défaut est LOCAL0. Veillez à vous reporter à la documentation système au sujet de syslog.

syslog_ident

Lorsque la sortie vers syslog est configurée, ce paramètre permet de déterminer le nom du programme utilisé pour identifier les messages de pgpool-II dans les traces enregistrées par syslog. La valeur par défaut est pgpool.

pid_file_name

Chemin complet vers le fichier qui contient le numéro d'identifiant du processus pgpool. La valeur par défaut est "/var/run/pgpool/pgpool.pid". Vous aurez besoin de redémarrer pgpool-II pour changer cette valeur.

print_timestamp

Ajoute un horodatage dans les traces lorsque cette valeur est à true. La valeur par défaut est true. Vous aurez besoin de recharger pgpool-II si vous changez cette valeur afin qu'elle soit prise en compte.

connection_cache

Cache les connexions à PostgreSQL lorsque cette valeur est configurée à true. La valeur par défaut est true.

health_check_timeout

pgpool-II essaie périodiquement de se connecter à PostgreSQL afin de détecter toute erreur sur les serveurs ou sur le réseau. Cette procédure de vérification d'erreurs est appelée « health check ». Si une erreur est détectée, pgpool-II essaie d'exécuter un failover ou une dégénération. Ce paramètre permet d'empêcher qu'un "health check" n'attende trop longtemps dans les cas où un câble réseau est débranché par exemple. La valeur du paramètre est en secondes. La valeur par défaut est de 20 secondes. 0 désactive cette fonctionnalité (dans ce cas, pgpool-II attend jusqu'à la fin du délai maximum configuré au niveau TCP/IP). Cette vérification nécessite une connexion supplémentaire à chacun des serveurs PostgreSQL. Du coup, il faut le prendre en compte dans la configuration du paramètre max_connections de chaque serveur PostgreSQL. Vous aurez besoin de recharger pgpool-II après toute modification de ce paramètre.

health_check_period

Ce paramètre précise l'intervalle de temps entre deux vérifications en secondes. La valeur par défaut est de 0, ce qui a pour effet de désactiver la vérification. Vous aurez besoin de recharger pgpool-II après tout changement de ce paramétrage.

health_check_user

Nom de l'utilisateur PostgreSQL utilisé pour exécuter la vérification. Cet utilisateur doit exister dans tous les serveurs PostgreSQL. Vous aurez besoin de recharger pgpool-II après tout changement de la valeur de ce paramètre.

failover_command

Ce paramètre spécifie la commande à exécuter lorsqu'un nœud est détaché. pgpool-II remplace les caractères spéciaux suivants avec les informations associées.

Caractère spécialDescription
%dID du processus serveur correspondant au nœud détaché
%hNom d'hôte du nœud détaché
%pNuméro de port du nœud détaché
%DRépertoire de l'instance PostgreSQL du nœud détaché
%MID du nœud de l'ancien maître
%mID du nœud du nouveau maître
%HNom d'hôte du nouveau nœud maître
%PID de l'ancien nœud primaire
%%Caractère '%'

Vous devez recharger pgpool.conf si vous changez la valeur de failover_command.

Lorsqu'une commande failover est exécutée, pgpool tue tous ses processus fils, ce qui fermera toutes les sessions actives à pgpool. Alors, pgpool invoque la commande failover_command et attend son exécution complète. Après cela, pgpool démarre de nouveaux processus fils et est alors à nouveau disponible pour accepter des connexions depuis les clients.

failback_command

Ce paramètre contient une commande à exécuter lors qu'un nœud est attaché. pgpool-II remplace les caractères spéciaux suivants avec les informations associées.

Caractère spécialDescription
%dID du processus serveur d'un nœud attaché
%hNom d'hôte d'un nœud attaché
%pNuméro de port d'un nœud attaché
%DRépertoire de l'instance PostgreSQL d'un nœud attaché
%MAncien nœud maître
%mNouveau nœud maître
%HNom d'hôte du nouveau nœud maître
%PID de l'ancien nœud primaire
%%Caractère '%'

Vous devez recharger pgpool.conf si vous changez le contenu de la commande failback_command.

fail_over_on_backend_error

Si ce paramètre est à true et qu'une erreur apparaît lors d'une écriture sur le canal de communication d'un processus serveur, pgpool-II déclenchera une procédure de failover. C'est le même comportement qu'avec les versions 2.2.x ou précédentes de pgpool-II. Si ce paramètre est à false, pgpool reportera une erreur dans ses fichiers de traces et déconnectera la session. Notez cependant que si ce paramètre est activé, pgpool effectuera aussi un failover lorsque la connexion à un processus serveur échoue ou lorsqu'il détecte l'arrêt du serveur PostgreSQL par un administrateur. Vous devez recharger pgpool.conf si vous changez cette valeur.

ignore_leading_white_space

Si ce paramètre est activé, pgpool-II ignorera les espaces en début de requête SQL lorsqu'il est dans le mode de répartition de charge. C'est particulièrement intéressant lorsqu'il est utilisé avec des API comme DBI/DBD::Pg qui ajoutent des espaces sans que l'utilisateur le demande. Vous aurez besoin de demander à pgpool-II de recharger sa configuration pour que ce paramètre soit pris en compte.

log_statement

Lorsque ce paramètre est activé, pgpool-II tracera les requêtes SQL qu'il reçoit dans son fichier de traces. Cela va produire des traces même si l'option debug n'est pas passée à pgpool-II au démarrage. Vous aurez besoin de recharger pgpool.conf pour que ce paramètre soit pris en compte.

log_per_node_statement

Similaire à log_statement, à l'exception qu'il écrit les traces de manière séparée par nœud. Cela peut se révéler très utile si vous voulez vous assurer, par exemple, que votre réplication fonctionne. Vous aurez besoin de recharger pgpool.conf pour que ce paramètre soit pris en compte.

log_hostname

Si ce paramètre est positionné à true, le nom de la commande affichée dans la sortie de ps sera le nom de l'hôte plutôt que son IP. De même, si log_connections est activé, le nom de l'hôte sera écrit dans les fichiers de trace plutôt que son IP. Ce paramètre est pris en compte au rechargement de pgpool.conf.

log_connections

Si ce paramètre est à true, toutes les connexions entrantes seront tracées dans les journaux applicatifs. Ce paramètre est pris en compte au rechargement de pgpool.conf.

enable_pool_hba

Si ce paramètre est à vrai, on utilisera le fichier pool_hba.conf pour l'authentification des clients. Voir la configuration de pool_hba.conf pour l'authentification des clients. Ce paramètre est pris en compte au rechargement de pgpool-II.

backend_hostname

Permet de spécifier à quel serveur PostgreSQL on se connecte. C'est utilisé par pgpool-II pour communiquer avec le serveur. Ce paramètre n'est lu qu'au démarrage du serveur pgpool-II.

Pour les communications TCP/IP, ce paramètre accepte soit un nom d'hôte, soit une adresse IP. Si ce dernier commence avec un slash, il spécifie un socket Unix plutôt qu'une adresse IP ; la valeur est alors le nom du répertoire dans lequel le fichier de socket UNIX est stocké. Si ce paramètre est vide (''), le comportement par défaut de pgpool-II est de se connecter à un socket UNIX stocké dans le répertoire /tmp.

On peut spécifier ici plusieurs serveurs en ajoutant un nombre à la fin du nom du paramète (par exemple backend_hostname0). Ce nombre est l'identifiant du nœud au sein de pgpool-II. Le premier nœud est toujours le nœud 0. Le serveur PostgreSQL qui se voit attribuer l'identifiant 0 sera appelé le serveur maître. Lorsque plusieurs serveurs sont définis et seulement pour certains modes, le service peut continuer même si le serveur maître est arrêté. Dans ce cas, c'est toujours le serveur qui a le plus petit identifiant de nœud et qui est encore disponible qui est alors promu serveur maître.

Si vous pensez n'utiliser qu'un seul serveur PostgreSQL, spécifiez-le avec backend_hostname0.

De nouveaux serveurs PostgreSQL peuvent être ajoutés grâce à ce paramètre mais Vous devez recharger le fichier de configuration. Par contre, les valeurs de ces paramètres ne pouvant être mises à jour, si vous les changez, vous devrez alors redémarrer pgpool-II.

backend_port

Spécifie le numéro de port des serveurs. Comme précédemment, on peut spécifier le port de plusieurs serveurs en ajoutant à la fin du nom du paramètre l'identifiant du nœud (par exemple backend_port0). Si vous n'utilisez qu'un seul serveur, vous devrez le spécifier par backend_port0.

Comme précédemment, vous pouvez ajouter de nouveaux paramètres concernant de nouveaux nœuds, et alors, un rechargement de la configuration suffira. Cependant, si vous mettez à jour des valeurs de paramètres existant, vous devrez redémarrer le serveur pgpool-II.

backend_weight

Spécifie le poids des serveurs pour la répartition de charge. On peut indiquer une valeur pour chacun des serveurs. Il suffit pour cela d'ajouter le numéro du serveur à la fin du nom du paramètre (par exemple backend_weight0). Si vous n'utilisez qu'un seul serveur PostgreSQL, utilisez le paramètre backend_weight0. Si vous êtes dans le mode RAW de pgpool-II, mettez toujours cette valeur à 1.

De nouveaux poids pour les backends peuvent être ajoutés pour de nouveaux nœuds. Cependant, si vous mettez à jour des valeurs de paramètres existant, vous devrez redémarrer le serveur pgpool-II.

À partir de pgpool-II 2.2.6/2.3, vous pouvez changer cette valeur par rechargement du fichier de configuration. Le nouveau paramétrage prendra alors effet uniquement pour les nouvelles sessions clientes. C'est très pratique si vous voulez empêcher toute requête envoyée aux serveurs esclaves de réaliser des tâches administratives en mode maître/esclave.

backend_data_directory

Précise le répertoire des données des serveurs PostgreSQL. Plusieurs serveurs peuvent être spécifiés en ajoutant un nombre à la fin du nom de paramètre (par exemple backend_data_directory0). Si vous ne pensez pas utiliser « online recovery », vous n'avez pas besoin de spécifier ce paramètre.

Des spécifications de répertoires de données PostgreSQL additionnels peuvent être ajoutés par rechargement du fichier de configuration. En revanche, leur valeur ne peut pas être mise à jour de cette façon. Du coup, vous devrez redémarrer pgpool-II si vous modifiez la valeur d'un paramètre déjà configuré.

ssl

Si ce paramètre est à "true", le support de SSL est activé à la fois pour les connexions clientes et les connexions aux serveurs PostgreSQL. Notez que ssl_key et ssl_cert doivent être renseignés pour que les connexions clientes puissent fonctionner en SSL.

SSL est désactivé par défaut. Notez que le support d'OpenSSL doit aussi avoir été configuré au moment de la compilation, comme c'est mentionné dans la section installation.

Le démon de pgpool-II doit être redémarré lorsqu'on met à jour les paramètres relatifs à SSL.

ssl_key

Chemin du fichier de clé privée pour les connexions clientes entrantes.

Il n'y a aucune valeur par défaut pour ce paramètre. S'il n'est pas modifié, le support de SSL sera désactivé pour les connexions clientes entrantes.

ssl_cert

Chemin complet vers le certificat public x509 à utiliser pour les connexions clientes entrantes.

Il n'y a aucune valeur par défaut pour ce paramètre. S'il n'est pas modifié, le support de SSL sera désactivé pour les connexions clientes entrantes.

debug_level

Niveau de verbosité des messages de débogage. 0 signifie aucun message, plus grand que 1 engendre des messages plus verbeux. La valeur par défaut est 0.

relcache_expire

Durée de vie en secondes d'une relation en cache. 0 signifie qu'il n'y a pas d'expiration (valeur par défaut). Ce cache de relations est utilisé pour cacher le résultat de requêtes effectuées sur le catalogue système de PostgreSQL pour obtenir diverses informations comme la structure des tables ou pour savoir si telle ou telle table est temporaire. Ce cache est maintenu dans une mémoire locale au processus fils de pgpool et est gardé aussi longtemps que le processus est en vie. Si un utilisateur modifie une table avec un ALTER TABLE, par exemple, ce cache n'est alors plus cohérent. À cet effet, le paramète relcache_expiration contrôle la durée de vie du cache.

Génération de certificats SSL

La manipulation des certificats n'est pas couvert dans ce document. La page Secure TCP/IP Connections with SSL (en anglais) sur le site PostgreSQL.org référence des documents qui expliquent en détail les commandes à taper pour engendrer des certificats auto-signés.

Failover dans le mode Raw

Le failover peut être accompli dans le mode Raw si plusieurs serveurs sont définis. pgpool-II accède en général au serveur spécifié par backend_hostname0 pendant son fonctionnement normal. Si le backend_hostname0 est en échec, quel que soit la raison, pgpool-II essaie d'accéder au serveur spécifié par backend_hostname1. En cas d'échec, pgpool-II essaie alors backend_hostname2, et ainsi de suite.

Mode pooling de connexions

Dans le mode pooling de connexions, toutes les fonctions du mode raw et du mode pooling de connexions peuvent être utilisées. Pour activer ce mode, configurez les paramètres du mode raw ainsi que les autres paramètres ci-après.

max_pool

Nombre maximum de connexions en cache dans les processus fils de pgpool-II. pgpool-II réutilise les connexions en cache si une connexion entrante se connecte à la même base de données avec le même nom d'utilisateur. Sinon, pgpool-II crée une nouvelle connexion au serveur PostgreSQL. Si le nombre de connexions en cache dépasse max_pool, la plus vieille des connexions sera supprimée et on utilisera cet emplacement ainsi libéré pour la nouvelle connexion. La valeur par défaut est 4. Faites bien attention au fait que le nombre total de connexions des processus pgpool-II aux serveurs PostgreSQL pourraient atteindre ainsi : num_init_children * max_pool. Ce paramètre n'est pris en compte qu'au démarrage du serveur pgpool-II.

connection_life_time

Durée de vie en seconde d'une connexion en cache. Une connexion en cache dont la durée de vie expire sera alors déconnectée. La valeur par défaut est 0, ce qui signifie que les connexions en cache ne seront jamais déconnectées.

reset_query_list

Spécifie les requêtes SQL envoyées à la connexion au serveur PostgreSQL lorsqu'une session se termine, côté client de pgpool-II. Plusieurs commandes peuvent être spécifiées en les séparant par un point-virgule. La valeur ci-dessous est la valeur par défault, mais elle peut être adaptée pour satisfaire vos besoins.

      reset_query_list = 'ABORT; DISCARD ALL'
      

Les commandes diffèrent dans chaque version de PostgreSQL. Voici les paramètres recommandés par version.

Version de PostgreSQLreset_query_list value
7.1 ou précédentesABORT
7.2 à 8.2ABORT; RESET ALL; SET SESSION AUTHORIZATION DEFAULT
8.3 et suivantesABORT; DISCARD ALL

  • "ABORT" n'est pas envoyé en dehors d'un bloc de transactions à partir de la 7.4.

Vous aurez besoin de recharger pgpool.conf après toute modification de ce paramètre pour que sa nouvelle valeur soit prise en compte.

Le failover dans le mode pooling de connexions

Le failover dans le mode pooling de connexions est identique à celui du mode raw.

Mode réplication

Ce mode permet la réplication des données entre les serveurs PostgreSQL. Les paramètres de configuration ci-dessous doivent être renseignés, en plus de tout ce qui a été vu plus haut.

replication_mode

Mettre ce paramètre à true active le mode de réplication. La valeur par défaut est false.

load_balance_mode

Lorsque ce paramètre est à true, les requêtes de type SELECT sont distribuées à chaque serveur PostgreSQL pour obtenir une répartition de la charge entre les serveurs. La valeur par défaut est false.

failover_if_affected_tuples_mismatch

Lorsque ce paramètre est positionné à true, si les serveurs PostgreSQL ne retournent pas le même nombre de lignes affectées lors d'un INSERT, UPDATE ou DELETE, les serveurs qui diffèrent de la valeur la plus fréquente sont « dégénérés » (NDT: ils ne sont alors plus jamais utilisés par pgpool-II, qui les considère comme incohérents). Si ce paramètre est à false, la session est terminée et les serveurs PostgreSQL ne sont pas « dégénérés ». La valeur par défaut est à false.

replication_stop_on_mismatch

Si ce paramètre est à true et si tous les serveurs PostgreSQL ne retournent pas le même type de paquet, les serveurs dont la valeur diffère du résultat le plus fréquent sont « dégénérés ». Un cas d'utilisation typique est une requête SELECT dans une transaction, avec replicate_select à true, qui retournerait un nombre d'enregistrements différent suivant les serveurs PostgreSQL. Les requêtes qui ne sont pas en SELECT pourraient aussi déclencher cette action. Par exemple, si un serveur PostgreSQL réussit un UPDATE alors que les autres échouent. Notez que pgpool-II n'examine pas le contenu des enregistrements retournés par un SELECT. Si ce paramètre est à false, la session est terminée et les serveurs PostgreSQL ne sont pas « dégénérés ». La valeur par défaut est false.

white_function_list

Permet de spécifier une liste de noms de fonctions, séparées par des virgules, qui ne font pas d'écritures dans la base de données. Tous les SELECTs qui font appel à des fonctions qui ne sont pas spécifiées dans cette liste ne seront ainsi jamais répartis entre les serveurs PostgreSQL, ni même répliqués dans le mode réplication. Dans le mode maître/esclave, de tels SELECTs sont envoyés au maître (ou primaire) uniquement.

Vous pouvez utiliser des expressions régulières dans la liste pour établir une correspondance à une famille de fonctions. Par exemple, si vous avez eu la bonne idée de préfixer toutes les fonctions de votre base qui ne font que des lectures avec 'get_' ou 'select_' par exemple, vous pourrez ainsi vous limiter à n'écrire que les deux expressions régulières dans ce paramètre :

white_function_list = 'get_.*,select_.*'
black_function_list

Permet de spécifier une liste de noms de fonctions, séparées par des virgules, qui font des écritures dans la base de données. Les SELECT qui utilisent les fonctions spécifiées dans cette liste ne seront jamais répartis entre les serveurs PostgreSQL, ni répliqués dans le mode de réplication. Dans le mode maître/esclave, de tels SELECT sont envoyés uniquement au maître.

Vous pouvez utiliser des expressions régulières dans la liste pour établir une correspondance avec une famille de fonctions. Par exemple, si vous avez eu la bonne idée de préfixer toutes les fonctions de votre base qui font des écritures avec 'set_','update_','delete_' ou 'insert_' par exemple, vous pourrez ainsi vous limiter à n'écrire que les expressions régulières suivantes dans ce paramètre :

black_function_list = 'nextval,setval,set_.*,update_.*,delete_.*,insert_.*'

Attention, une seule de ces deux listes ne peut être renseignée dans la configuration de pgpool-II. Autrement dit, vous devez opter pour l'un ou l'autre des paramètres : autoriser de manière explicite, ou interdire de manière explicite. De préférence, optez pour la sécurité d'autoriser explicitement, c'est-à-dire utiliser le paramètre white_function_list. En effet, en cas d'oubli d'une fonction en écriture dans le paramètre black_function_list, vous risquez de demander l'exécution d'une fonction en écriture sur un serveur en lecture seule, dans le mode maître/esclave par exemple.

Avant la version 3.0 de pgpool-II, les fonctions nextval() et setval() étaient connues pour leurs écritures dans la base de données. Vous pouvez émuler ce comportement en utilisant les deux paramètres vus précédemment de la façon suivante :

white_function_list = ''
black_function_list = 'nextval,setval,lastval,currval'

Notez que l'on a lastval() et currval() en plus des nextval() et setval(). Bien que lastval() et currval() ne soient pas des fonctions qui provoquent des écritures, il vaux mieux les ajouter pour éviter toute erreur dans le cas où ces fonctions seraient accidentellement réparties entre les différents nœuds. Ainsi, les ajouter à la black_function_list permettra d'éviter qu'elles soient réparties.

replicate_select

Lorsque ce paramètre est à true, pgpool-II va répliquer les SELECT dans le mode de réplication. Si c'est à false, pgpool-II va les envoyer uniquement au serveur maître (primaire). La valeur par défaut est false.

Si une requête SELECT est à l'intérieur d'un bloc de transaction explicite, replicate_select et load_balance_mode auront un effet sur le fonctionnement de la réplication. Les détails sont expliqués ci-dessous.

Le SELECT est à l'intérieur d'un bloc de transaction O O O N N N O N
replicate_select = true O O N N O O N N
load_balance_mode = true O N N N O N O O
resultats (R:réplication, M:envoyé au maître uniquement, L:réparti) R R M M R R M L

insert_lock

Si on réplique une table qui utilise le type de données SERIAL, la valeur du SERIAL pourrait être différente entre les serveurs PostgreSQL. On peut éviter ce problème en verrouillant la table de manière explicite (bien que le parallélisme des transactions sera alors sévèrement dégradé). Pour arriver à cela, les changements suivants doivent être faits :

      INSERT INTO ...
      

à

      BEGIN;
      LOCK TABLE ...
      INSERT INTO ...
      COMMIT;
      

Lorsque insert_lock est à true, pgpool-II ajoute automatiquement les requêtes ci-dessus à chaque fois qu'un INSERT est exécuté. Si on est alors déjà dans une transaction, il ajoute alors simplement un LOCK TABLE.

À partir de pgpool-II 2.2, la détection des tables qui ont un SERIAL ou non est automatique. Ainsi, seules les tables qui ont un SERIAL sont verrouillées de manière exclusive.

pgpool-II 3.0 utilise désormais un verrou de ligne sur la relation de la séquence, plutôt qu'un verrou de table exclusif. Cela minimise les conflits sur les verrous, comme par exemple VACUUM (direct ou via autovacuum).

Si vous souhaitez un contrôle plus fin (par requête) :

  1. positionnez insert_lock à true, et ajoutez /*NO INSERT LOCK*/ au début d'une requête INSERT pour laquelle vous ne voulez pas qu'un verrou exclusif de table ne soit ajouté.
  2. positionnez insert_lock à false, et ajoutez /*INSERT LOCK*/ au début d'une requête INSERT pour laquelle vous voulez provoquer un verrouillage exclusif de la table.

La valeur par défaut est false. Si insert_lock est activé, les tests de régression pour PostgreSQL 8.0 échoueront dans les transactions, droits, règles (rules) et ALTER TABLE. La raison en est que pgpool-II essaie de verrouiller une vue pour le test sur les règles, ce qui a pour conséquence l'erreur suivante :

      ! ERROR: current transaction is aborted, commands ignored until
      end of transaction block
      

Par exemple, le test sur les transactions essaie un INSERT dans une table qui n'existe pas, et pgpool-II essaie d'acquérir un verrou exclusif avant cela. La transaction sera alors interrompue et la requête d'INSERT qui suit produira le message ci-dessus.

recovery_user

Ce paramètre permet de spécifier l'utilisateur PostgreSQL à utiliser pour le « online recovery ». Il peut être changé sans avoir besoin de redémarrer pgpool-II.

recovery_password

Ce paramètre permet de spécifier le mot de passe de l'utilisateur spécifié dans le paramètre ci-dessus, à savoir recovery_user, qui est utilisé lors du « online recovery ». Comme le paramètre précédent, il peut être changé sans avoir à redémarrer le serveur pgpool-II.

recovery_1st_stage_command

Ce paramètre permet de préciser une commande à exécuter pour la première phase du « online recovery ». Le fichier de commandes spécifié ici doit être placé à la racine du répertoire des données de l'instance PostgreSQL, pour des raisons de sécurité. Par exemple, si recovery_1st_stage_command = 'sync-command', alors pgpool-II exécute $PGDATA/sync-command. Notez que pgpool-II accepte les connexions et les requêtes alors que recovery_1st_stage command est en cours d'exécution. On peut ainsi lire et écrire dans la base de données pendant cette première phase du « online recovery ».

Ce paramètre peut être changé sans avoir à redémarrer pgpool-II.

recovery_2nd_stage_command

Ce paramètre spécifie une commande à exécuter lors de la deuxième phase du « online recovery ». Ce fichier de commandes doit être placé à la racine du répertoire des données de l'instance PostgreSQL pour des raisons de sécurité. Par exemple, si recovery_2nd_stage_command = 'sync-command', alors pgpool-II exécute $PGDATA/sync-command. Notez que pgpool-II n'accepte pas de connexions ou d'exécution de requêtes pendant que recovery_2nd_stage_command est en cours d'exécution. Ainsi, si un client reste connecté pendant une longue période, rien ne sera exécuté. En effet, pgpool-II attends que tous les clients aient fermé leurs connexions pour exécuter cette seconde phase du « online recovery ». La commande n'est donc exécutée que lorsqu'il n'y a plus aucun client de connecté.

Ce paramètre peut être changé sans redémarrer pgpool-II.

recovery_timeout

pgpool n'accepte plus de nouvelle connexion pendant la seconde phase du « online recovery ». Si un client essaie de se connecter à pgpool-II pendant un « online recovery », il devra attendre la fin de ce dernier.

Ce paramètre spécifie un délai au terme duquel le « online recovery » sera annulé s'il n'est pas terminé. Après l'annulation, pgpool-II acceptera alors de nouveau les connexions. La valeur 0 désactive cette fonctionnalité.

Ce paramètre peut être changé sans avoir à redémarrer pgpool-II.

client_idle_limit_in_recovery

Similaire à client_idle_limit. Cependant, il n'agit que lors de la seconde phase du « online recovery ». Un client qui aura été inactif pendant client_idle_limit_in_recovery secondes depuis sa dernière requête sera déconnecté. Ce paramètre permet d'éviter que le « online recovery » ne soit perturbé par un client inactif, ou si la connexion TCP/IP entre le client et pgpool tombe de manière accidentelle (un câble réseau défectueux par exemple). Si ce paramètre est à -1, le client est déconnecté immédiatement. La valeur par défaut de ce paramètre est 0, ce qui signifie que cette fonctionalité est désactivée.

Si vos clients sont très actifs, pgpool-II ne pourra jamais entrer dans la seconde phase du « online recovery », quelle que soit la valeur de client_idle_limit_in_recovery que vous aurez choisie. Dans ce cas, vous pouvez paramétrer client_idle_limit_in_recovery à -1 afin que pgpool-II puisse déconnecter immédiatement des clients aussi actifs avant de passer à la seconde phase du « online recovery ».

Vous devez recharger la configuration de pgpool-II si vous changer la valeur de client_idle_limit_in_recovery.

lobj_lock_table

Ce paramètre spécifie un nom de table utilisé pour le contrôle de la réplication des « large objects ». Si elle est spécifiée, pgpool-II verrouillera cette table, et génèrera un identifiant de « large object » en regardant dans la table pg_largeobject du catalogue système, et enfin, appellera lo_create pour créer le « large object ». Cette procédure garantie que pgpool-II obtiendra le même identifiant de « large object » sur tous les serveurs PostgreSQL lorsque pgpool-II est dans le mode réplication. Notez que PostgreSQL 8.0 et ultérieur n'a plus de fonction lo_create. Du coup, cette fonctionalité est pas utilisable pour ces versions.

Un appel à la fonction de la libpq lo_creat() utilisera cette fonctionalité. De même, la création de « large objects » via l'API Java (driver JDBC) devrait fonctionner, tout comme l'API PHP (pg_lo_create, ou API similaire dans la bibliothèque de PHP, comme PDO), et ce genre d'API similaires dans plusieurs langages de programmation qui sont réputées pour utiliser un protocole similaire.

Les opérations suivantes de création d'un « large object » ne fonctionneront pas :

  • lo_create de la libpq
  • l'API d'un langage qui utilise lo_create
  • la fonction lo_import dans le serveur PostgreSQL
  • SELECT lo_creat

Peu importe le schéma où est stockée la table lobj_lock_table, celle-ci doit en revanche être accessible en écriture à tous les utilisateurs. Voici un exemple de création d'une telle table :

CREATE TABLE public.my_lock_table ();
GRANT ALL ON public.my_lock_table TO PUBLIC;

La table spécifiée par lobj_lock_table doit être créée à l'avance. Vous pouvez par exemple la créer dans la base template1 afin que toute base de données créée par la suite en dispose.

Si lobj_lock_table contient une chaîne vide (''), la fonctionalité est désactivée. Du coup, la réplication des « large objects » ne fonctionnera pas. La valeur par défaut de ce paramètre est justement la chaîne vide ('').

Pré-requis pour la répartition de charge

Pour qu'une requête soit répartie, les pré-requis suivants doivent être respectés :

  • Version 7.4 ou ultérieure de PostgreSQL
  • La requête ne doit pas être déclarée explicitement (c'est-à-dire qu'on ne doit pas être dans un bloc BEGIN ~ END)
  • Il ne s'agit pas d'un SELECT nextval ou d'un SELECT setval
  • Il ne s'agit pas d'un SELECT INTO
  • Il ne s'agit pas d'un SELECT FOR UPDATE ou FOR SHARE
  • La requête commence par un SELECT ou COPY TO STDOUT, EXPLAIN, EXPLAIN ANALYZE SELECT... le paramètre ignore_leading_white_space = true permettra d'ignorer tous les éventuels espaces présents avant la requête.

Notez que vous pouvez interdire de manière explicite la répartition d'une charge sur une requête SELECT en ajoutant un commentaire au début de la requête SELECT (quel que ce soit ce commentaire). Par exemple :

  /*REPLICATION*/ SELECT ...

Merci de lire attentivement la page replicate_select au sujet de la réplication. De même, étudiez attentivement ce schéma qui explique comment pgpool-II détermine à quel serveur PostgreSQL envoyer telle ou telle requête.

Attention : le connecteur JDBC a une option autocommit. Si autocommit est à false, le connecteur JDBC envoie un BEGIN et un COMMIT lui-même. Ainsi, pgpool-II ne pourra faire aucune répartition de charge. Vous devez alors appeler setAutoCommit(true) pour activer l'autocommit.

Failover dans le mode Réplication

pgpool-II désactive un serveur « mort » et le service continue, à condition qu'il y ait au moins un serveur PostgreSQL en vie.

Mode Maître-Esclave

Ce mode est utilisé lorsque pgpool-II est couplé avec un autre outil de réplication de type maître/esclave(s) (comme Slony-I ou le Streaming Réplication intégré à PostgreSQL). Cet outil est alors responsable de la réplication des données. L'information sur les serveurs PostgreSQL doit être renseignée (les paramètres backend_hostname, backend_port, backend_weight et backend_data_directory), de la même façon que dans le mode réplication. De plus, il faut paramétrer master_slave_mode et load_balance_mode à true. pgpool-II enverra alors les requêtes qui doivent être répliquées au serveur PostgreSQL maître, et les autres requêtes seront réparties parmi les différents serveurs lorsque c'est possible. L'algorithme de pgpool-II prend bien sûr en compte les requêtes qui ne peuvent être réparties ; elles sont alors systématiquement envoyées au serveur maître.

Dans le mode maître-esclave, les DDL et DML pour une table temporaire ne peuvent être exécutées que sur le serveur maître. Vous pouvez forcer un SELECT à ne s'exécuter que sur le maître en ajoutant un commentaire /*NO LOAD BALANCE*/ devant le SELECT.

Dans le mode maître-esclave, vous devez positionner replication_mode à false et master_slave_mode à true.

Le mode maître-esclave a un sous-mode piloté par le paramètre 'master_slave_sub_mode'. Il vaut par défaut slony et convient si vous utilisez Slony-I. Vous pouvez aussi le paramétrer à stream si vous utilisez le système de réplication intégré à PostgreSQL (le Streaming Replication). Le fichier de configuration d'exemple pour le sous-mode Slony-I est pgpool.conf.sample-master-slave, et celui concernant la Streaming Replication est pgpool.conf.sample-stream.

Vous devez redémarrer pgpool-II si vous changez l'un des paramètres vu précédemment.

Vous devrez probablement aussi renseigner les paramètres white_function_list et black_function_list si vous voulez contrôler plus finement la répartition de charge dans le mode maître-esclave. Reportez-vous à white_function_list pour plus de détails.

Streaming Replication

Comme nous l'avons vu précédemment, pgpool-II peut fonctionner de pair avec la Streaming Replication, qui est disponible depuis la version 9.0 de PostgreSQL. Pour l'utiliser, il faut activer le paramètre master_slave et positionner le paramètre master_slave_sub_mode1 à stream. pgpool-II suppose que le Streaming Replication fonctionne et que les serveurs PostgreSQL esclaves sont en Hot Standby, ce qui signifie que les bases de données sont ouvertes en lecture seule sur ces derniers. Les directives suivantes peuvent être utilisées dans ce mode :

  • delay_threshold

    Permet de spécifier le décalage maximum toléré entre le serveur maître et un serveur esclave dans une réplication, exprimé en octets de journaux de transactions. Si le décalage dépasse delay_threshold, pgpool-II n'envoie alors plus de SELECT au serveur(s) esclave(s). Tout est alors envoyé au serveur maître, même si la répartition de charge est activée, jusqu'à ce que le(s) serveur(s) esclave(s) soit(soient) en deçà du décalage maximum autorisé. Si delay_threshold est à 0 ou si le test de vie est désactivé, ce test de décalage n'est jamais fait. Ce dernier est effectué tous les health_check_period. La valeur par défaut pour delay_threshold est 0. Vous devez recharger la configuration de pgpool-II si vous changez cette directive.

  • log_standby_delay

    Permet de spécifier comment le décalage de réplication est tracé dans le journal applicatif de pgpool-II. Si none est spécifié ici, rien n'est écrit. Si always est spécifié, alors le décalage sera tracé à chaque fois que le test est effectué. Si if_over_threshold est spécifié, alors le décalage est tracé uniquement lorsqu'il dépasse le delay_threshold. La valeur par défaut pour log_standby_delay est none. Vous devez recharger la configuration de pgool-II si vous changez ce paramètre.

    Vous pouvez aussi superviser le décalage éventuel de la réplication en utilisant la commande "show pool_status".

Le failover avec la Streaming Replication

Dans le mode maître/esclave avec la Streaming Replication, si le nœud primaire ou le nœud en attente s'arrête, pgpool-II peut être configuré pour exécuter un Failover. Les nœuds peuvent alors être attachés automatiquement sans configuration ou opérations complémentaires. Alors qu'il est en pleine réplication [~], le nœud en attente vérifie régulièrement si un fichier de déclenchement existe. S'il le trouve, le nœud en attente sort de son mode réplication et s'ouvre en mode lecture/écriture. En utilisant ce mécanisme, on peut avoir une base de données en attente qui prends le relais quand le nœud primaire tombe.

Attention : si vous pensez utiliser plusieurs nœuds en mode standby, il est recommandé de définir le paramètre delay_threshold pour empêcher tout requête dirigée vers d'autres nœuds en standby de récupérer des données plus vieilles.

Si un second nœud en standby prends le relais quand le premier nœud en standby avait déjà pris le relais, vous pourriez avoir des données erronnées en provenance du second standby. Nous vous recommandons de ne pas utiliser ce genre de configuration.

Voici commment configurer un mécanisme de Failover.

  1. Il faut créer un script de Failover quelque part sur le système, par exemple dans /usr/local/pgsql/bin, puis le rendre exécutable.
    $ cd /usr/loca/pgsql/bin
    $ cat failover_stream.sh
    #! /bin/sh
    # Commandes pour faire un Failover en mode Streaming Replication
    # Ce script suppose que le nœud Maitre est le 0 et 1 le standby
    # 
    # Si le Standby s'arrête, ne rien faire. Si le Primaire s'arrête, créer
    # un fichier de déclenchement afin que le standby prenne le relais sur le 
    # nœud Primaire.
    #
    # Arguments: 
    #   $1: identifiant du nœud qui ne répond plus
    #   $2: nom d'hôte du nouveau maître 
    #   $3: chemin vers le fichier trigger 
    
    failed_node=$1
    new_master=$2
    trigger_file=$3
    
    # Ne rien faire si c'est le standby qui tombe
    if [ $failed_node = 1 ]; then
    	exit 0;
    fi
    
    # Créer un fichier de déclenchement
    /usr/bin/ssh -T $new_master /bin/touch $trigger_file
    
    exit 0;
    
    chmod 755 failover_stream.sh
    
  2. Il faut à présent définir la commande failover_commmand dans le fichier pgpool.conf :
    failover_command = '/usr/local/src/pgsql/9.0-beta/bin/failover_stream.sh %d %H /tmp/trigger_file0'
    
  3. Et créer le fichier recovery.conf sur le nœud en standby. Un exemple de fichier recovery.conf est disponible dans le répertoire d'installation de PostgreSQL. Son nom complet est "share/recovery.conf.sample". Copier recovery.conf.sample en recovery.conf dans le répertoire de base de PostgreSQL et l'éditer comme suit.
    standby_mode = 'on'
    primary_conninfo = 'host=nom_du_nœud_primaire user=postgres'
    trigger_file = '/tmp/trigger_file0'
    
  4. Ajuster le postgresql.conf sur le nœud primaire. La configuration ci-dessous est donneé à titre indicatif, vous devrez probablement l'ajuster pour votre environnement.
    wal_level = hot_standby
    max_wal_senders = 1
    
  5. Définir pg_hba.conf sur le nœud Primaire. La configuration ci-dessous est donnée à titre indicatif, vous devrez probablement l'ajuster pour votre environnement.
    host	replication	postgres		192.168.0.10/32		trust
    

Démarrez PostgreSQL sur les nœuds primaire et secondaire pour initialiser la réplication. Si le nœud primaire venait à tomber, le nœud secondaire prendra automatiquement le relais, en tant que nouveau nœud primaire, et sera alors prêt à recevoir les requêtes en écriture.

Streaming Replication

Lorsqu'on utilise la Streaming Replication et le Hot Standby, il est important de déterminer les requêtes pouvant être envoyées sur le nœud principal ou sur le nœud en standby (secondaire), et les requêtes qui ne peuvent pas l'être. Le mode Streaming Replication de pgpool-II se charge complètement de cette problématique. Dans ce chapitre, nous expliquerons comment pgpool-II parvient à cela.

Nous distinguons les requêtes qui devraient être envoyées à tel ou tel nœud en les examinant.

  • Les requêtes suivantes devraient être envoyées au nœud primaire uniquement :
    • INSERT, UPDATE, DELETE, COPY FROM, TRUNCATE, CREATE, DROP, ALTER, COMMENT
    • SELECT ... FOR SHARE | UPDATE
    • SELECT dans un niveau d'isolation transactionnel de type SERIALIZABLE
    • LOCK, commande plus stricte que ROW EXCLUSIVE MODE
    • Quelques commandes transactionnelles :
      • BEGIN READ WRITE, START TRANSACTION READ WRITE
      • SET TRANSACTION READ WRITE, SET SESSION CHARACTERISTICS AS TRANSACTION READ WRITE
      • SET transaction_read_only = off
    • Les commandes relatives à la validation en deux phases : PREPARE TRANSACTION, COMMIT PREPARED, ROLLBACK PREPARED
    • LISTEN, UNLISTEN, NOTIFY
    • VACUUM
    • Quelques fonctions liées aux séquences (nextval et setval)
    • Les commandes de création de « Large Objects »
  • Ces requêtes peuvent être envoyées à la fois au nœud primaire et au nœud en standby. Si la répartition de charge est activée, ce type de requêtes peut être envoyé au nœud en standby. Cependant, si le paramètre delay_threshold est défini et que le délai dans la réplication est supérieur au delay_threshold, les requêtes sont envoyées au nœud primaire.
    • tout SELECT non listé ci-dessus
    • COPY TO
    • DECLARE, FETCH, CLOSE
    • SHOW
  • Les requêtes suivantes sont envoyées à la fois au nœud primaire et secondaire :
    • SET
    • DISCARD
    • DEALLOCATE ALL

Dans une transaction explicite :

  • Toute transaction commençant par une commande comme BEGIN est envoyée au nœud primaire.
  • Tout SELECT qui survient immédiatement après, ainsi que toutes les requêtes qui peuvent être envoyées aussi bien au primaire qu'au secondaire, sont réparties entre les nœuds.
  • Toute commande qui ne peut être exécutée sur un nœud en standby (secondaire) comme un INSERT sont envoyées uniquement au primaire. Après toute commande de ce type, absolument tous les ordres SQL sont envoyés au nœud primaire. En effet, les SELECT suivant pourraient vouloir voir les résultats d'un INSERT immédiatement. Ce comportement continue jusqu'à ce que la transaction se ferme ou soit interrompue.

Dans le protocole étendu, il est possible de déterminer si la requête peut être envoyée au nœud en standby ou pas dans le mode de répartition de charge au moment où on analyse la requête. Les rêgles sont les mêmes que dans le protocole non-étendu. Par exemple, les INSERT sont envoyés au primaire, ainsi que toute requête qui suivra.

Note : si l'analyse d'une requête en SELECT est envoyée sur le standby à cause de la répartition de charge et qu'une requête en modification de données, comme un INSERT est envoyé à pgpool-II, alors le SELECT analysé devra être exécuté sur le nœud primaire. Cependant, on analyse de nouveau le SELECT sur le nœud primaire.

Enfin, les requêtes qui semblent douteuses ou possiblement en erreur sont envoyées sur le nœud primaire.

Online recovery avec la Streaming Replication

Dans le mode maître/esclave avec la Streaming Replication, on peut procéder à une restauration à chaud (« Online recovery »). Cependant, seul un nœud en standby peut être ainsi récupéré. On ne peut pas reconstruire un nœud primaire. Pour ce faire, il faudra stopper toutes les bases de données, ainsi que pgpool-II, puis restaurer le nœud primaire à partir d'une sauvegarde.

Voici les étapes.

  1. Définir le paramètre recovery_user. C'est souvent postgres.
    recovery_user = 'postgres'
    
  2. Définir le paramètre recovery_password pour que le recovery_user puisse se connecter à la base.
    recovery_password = 't-ishii'
    
  3. Définir le paramètre recovery_1st_stage_command. Le script pour cette étape doit procéder à une sauvegarde du nœud primaire et à sa restauration sur le nœud en standby. Placez ce script à l'intérieur du répertoire de données du nœud primaire et donnez-lui les droits nécessaires pour être exécutable. Un script d'exemple est disponible : basebackup.sh, avec une configuration simple d'un primaire et d'un standby. Il faut configurer SSH pour que l'utilisateur indiqué dans le paramètre recovery_user puisse se connecter depuis le primaire vers le standby sans qu'un mot de passe ne soit demandé.
    recovery_1st_stage_command = 'basebackup.sh'
    
  4. Laisser le paramètre recovery_2nd_stage_command vide.
    recovery_2nd_stage_command = ''
    
  5. Installer à présent les fonctions C et SQL nécessaires dans chacune des bases de données pour que le « online recovery » fonctionne.

    # cd pgpool-II-x.x.x/sql/pgpool-recovery
    # make
    # make install
    # psql -f pgpool-recovery.sql template1
    
  6. Après avoir terminé le « online recovery », pgpool-II démarre PostgreSQL sur le nœud standby. À cet effet, il faut installer un script sur chacun des nœuds. Un script d'exemple est inclus dans le répertoire sample du répertoire des sources. Ce script utilise SSH. Il faudra permettre à l'utilisateur indiqué dans le paramètre recovery_user de se connecter depuis le primaire vers le standby sans qu'un mot de passe ne soit demandé.

C'est tout. On peut à présent utiliser pcp_recovery_node (dès qu'un nœud en standby s'arrête) ou alors cliquer sur le bouton « recovery » dans l'interface de pgpoolAdmin pour exécuter un « Online Recovery ».

Mode parallèle

Ce mode permet l'exécution en parallèle de requêtes. Les tables peuvent être découpées, et les données distribuées sur chaque nœud. De plus, les fonctionnalités de réplication et de répartition de charge peuvent être utilisées avec ce mode, en même temps. Dans le mode parallèle, replication_mode et load_balance_mode sont positionnés à true dans le fichier pgpool.conf, alors que master_slave est positionné à false, et que parallel_mode est positionné à true. Si ce paramètre est changé, il faut redémarrer pgpool-II pour qu'il soit pris en compte.

Configuration de la base système

Pour utiliser le mode parallèle, la base système doit être configurée correctement. La base système contient des règles, stockées dans une table, pour choisir le nœud PostgreSQL approprié auquel envoyer les données. La base de données système n'a pas besoin d'être créée sur le même nœud que pgpool-II. La configuration de cette dernière est faite dans pgpool.conf.

system_db_hostname

Nom de l'hôte où la base de données système réside. Une chaîne vide dans ce paramètre ('') signifie que celle-ci est sur le même nœud que pgpool-II, et sera alors accédée via un socket UNIX.

system_db_port

Numéro de port de la base de données système

system_dbname

Les règles de partitionnement et autres informations seront définies dans la base de données spécifiée ici. La valeur par défaut est 'pgpool'.

system_db_schema

Les règles de partitionnement et autres informations seront stockées dans le schéma spécifié ici. La valeur par défaut est 'pgpool_catalog'.

system_db_user

Nom de l'utilisateur qui se connecte à la base de données système.

system_db_password

Mot de passe pour l'utilisateur de la base de données système. Si aucun mot de passe n'est nécessaire, laissez une chaîne vide dans ce paramètre ('').

ssl_ca_cert

Chemin complet vers un fichier au format PEM contenant un ou plusieurs certificats CA, qui doivent être utilisés pour vérifier le certificat du serveur. C'est analogue à l'option -CAfile de la commande verify(1) d'OpenSSL.

Il n'y a pas de valeur par défaut pour cette option. Du coup, aucune vérification n'a lieu par défaut. Par contre, une vérification sera réalisée si une valeur a été définie pour ssl_ca_cert_dir.

ssl_ca_cert_dir

Chemin vers un répertoire qui contient les certificats CA au format PEM, qui peuvent être utilisés pour vérifier le certificat du serveur. C'est analogue à l'option -CAfile de la commande verify(1) d'OpenSSL.

Il n'y a pas de valeur par défaut pour cette option. Du coup, aucune vérification n'a lieu par défaut. Par contre, une vérification sera réalisée si une valeur a été définie pour ssl_ca_cert.

Configuration initiale de la base de données système

Il faut d'abord créer la base de données et le schéma spécifiés dans le fichier pgpool.conf. Un script d'exemple peut être trouvé dans $prefix/share/system_db.sql. Si vous avez indiqué un nom différent pour la base de données ou le schéma, adaptez ce script en conséquence.

psql -f $prefix/share/system_db.sql pgpool

Enregistrement d'une règle de partitionnement

Les règles pour le partitionnement des données doivent être enregistrées dans la table pgpool_catalog.dist_def.

CREATE TABLE pgpool_catalog.dist_def(
dbname TEXT,                                              -- nom de la base
schema_name TEXT,                                         -- nom du schéma
table_name TEXT,                                          -- nom de la table
col_name TEXT NOT NULL CHECK (col_name = ANY (col_list)), -- nom de la colonne 
de la clé de partitionnement
col_list TEXT[] NOT NULL,                                 -- noms des
attributs de la table
type_list TEXT[] NOT NULL,                                -- types de
données de la table des attributs
dist_def_func TEXT NOT NULL,                              -- nom de la
fonction pour la règle de partitionnement
PRIMARY KEY (dbname,schema_name,table_name)
);

Enregistrement d'une règle de réplication

Les tables qui ne sont pas distribuées doivent être répliquées. Lorsqu'une requête fait la jointure d'une table distribuée avec une autre table, pgpool récupère l'information de réplication dans la table pgpool_catalog.replicate_def. Ainsi, une table est soit répliquée, soit ditribuée.

CREATE TABLE pgpool_catalog.replicate_def(
	dbname TEXT,	    --nom de la base
	schema_name TEXT,	--nom du schéma
	table_name TEXT,	--nom de la table
	col_list TEXT[] NOT NULL,	-- nom des attributs de la table
	type_list TEXT[] NOT NULL,	-- types de données des attributs de
la table
	PRIMARY KEY (dbname,schema_name,table_name)
);

Exemple basé sur le partitionnement des tables de pgbench

pgbench est un outil simple de tests de performance de PostgreSQL, disponible dans le répertoire contrib de PostgreSQL.

Dans cet exemple, la table accounts est partitionnée, les tables branches et tellers sont répliquées. Les tables accounts et branches sont jointes sur la colonne bid. La table branches est enregistrée dans la table de réplication. Si les trois tables (accounts, branches et tellers) doivent être jointes, il est nécessaire d'enregistrer aussi une règle de réplication pour la table tellers.

INSERT INTO pgpool_catalog.dist_def VALUES (
	'pgpool',
	'public',
	'accounts',
	'aid',
	ARRAY['aid','bid','abalance','filler'],
	ARRAY['integer','integer','integer','character(84)'],
	'pgpool_catalog.dist_def_accounts'
);

INSERT INTO pgpool_catalog.replicate_def VALUES (
	'pgpool',
	'public',
	'branches',
	ARRAY['bid','bbalance','filler'],
	ARRAY['integer','integer','character(84)']
);

La règle de partitionnement (ici, pgpool_catalog.dist_def_accounts) prends une valeur pour la colonne qui sert de clé de partitionnement, et retourne le numéro du nœud de la base de données correspondante. Notez que l'identifiant des nœuds doit commencer par 0. Voici un exemple de cette fonction pour pgbench.

CREATE OR REPLACE FUNCTION pgpool_catalog.dist_def_accounts (val ANYELEMENT) RETURNS INTEGER AS '
SELECT CASE WHEN $1 >= 1 and $1 <= 30000 THEN 0
WHEN $1 > 30000 and $1 <= 60000 THEN 1
ELSE 2

Configuration de pool_hba.conf pour l'authentification des clients (HBA)

Tout comme le fichier pg_hba.conf pour PostgreSQL, pgpool a la même fonctionnalité d'authentification des clients, qui est basée sur un fichier appelé pool_hba.conf.

Lorsque pgpool est installé, le fichier pool_hba.conf.sample est installé dans /usr/local/etc, qui est le répertoire par défaut des fichiers de configuration. Il faut copier pool_hba.conf.sample en pool_hba.conf puis l'éditer si nécessaire. Par défaut, l'authentification par pool_hba est activée. Se reporter à « 6. Configuration de pgpool.conf » pour plus de détails.

Le format du fichier pool_hba.conf est très similaire à celui du fichier pg_hba.conf de PostgreSQL.

    local      DATABASE  USER  METHOD  [OPTION]
    host       DATABASE  USER  CIDR-ADDRESS  METHOD  [OPTION]

Voir pool_hba.conf.sample pour une explication détaillée de chaque champ.

Voici les limitations de pool_hba.

  • la connexion de type hostssl n'est pas supportée
  • Bien que hostssl soit invalide, pgpool-II 2.3 et supérieur supporte SSL. Voir SSL pour plus de détails.

  • samegroup dans la colonne DATABASE n'est pas supporté
  • Comme pgpool ne sait rien à propos des utilisateurs déclarés dans le serveur PostgreSQL, le nom de la base de données est testé simplement par rapport aux entrées de la colonne DATABASE dans le fichier pool_hba.conf.

  • les noms de groupes suivis du signe + pour la colonne USER ne sont pas supportés
  • Cela est dû à la même raison que pour samegroup décrit ci-dessus. Un nom d'utilisateur est testé simplement par rapport aux entrées dans la colonne USER du fichier pool_hba.conf.

  • l'IPv6 pour l'adresse/masque dans la colonne IP n'est pas supporté
  • À ce jour, pgpool ne supporte pas l'IPv6.

  • Seules les méthodes trust, reject, md5 et pam sont supportées dans la colonne METHOD
  • Encore une fois, c'est pour la même raison que pour samegroup (décrit ci-dessus) : pgpool n'a pas accès aux informations sur les utilisateurs et mots de passes stockés dans le serveur PostgreSQL.

    Pour utiliser l'authentification md5, il faudra enregistrer votre nom d'utilisateur et son mot de passe dans pool_passwd. Voir Authentification / Contrôle d'accès pour plus de détails.

Notez que tout ce qui est décrit dans cette section concerne l'authentification entre un client et pgpool ; un client doit toujours passer à travers le processus d'authentification de PostgreSQL. Bien que pool_hba soit concerné, cela n'a pas d'importance si un nom d'utilisateur et/ou de base de données donné par un client (i.e. psql -U testuser testdb) existe ou non dans le serveur. pool_hba ne regarde en effet que si une correspondance est trouvée dans le fichier pool_hba.conf.

L'authentification PAM fonctionne grâce à l'information sur l'utilisateur trouvée sur le serveur où pgpool est exécuté. Pour activer le support de PAM dans pgpool, spécifier l'option "--with-pam" lors de la phase de configuration de la compilation :

    configure --with-pam

Pour activer l'authentification PAM, on a besoin de créer un fichier de configuration du service pour pgpool dans le répertoire de configuration de PAM sur le système (qui est en général /etc/pam.d). Un fichier d'exemple nommé share/pgpool.pam est présent dans le répertoire d'installation.

Configuration de la méthode de cache de requêtes

Le cache de requêtes est utilisable dans tous les modes de pgpool-II. Son activation dans le fichier pgpool.conf se fait de la manière suivante :

enable_query_cache = true

Cependant, il faut aussi créer la table suivante dans la base de données système de pgpool-II :

CREATE TABLE pgpool_catalog.query_cache (
  hash TEXT,
  query TEXT,
  value bytea,
  dbname TEXT,
  create_time TIMESTAMP WITH TIME ZONE,
  PRIMARY KEY(hash, dbname)
);

Notez qu'il peut aussi être nécessaire de modifier le nom du schéma dans l'exemple ci-dessus si pgpool_catalog n'est pas utilisé.

Démarrage et arrêt de pgpool-II

Tous les serveurs PostgreSQL doivent être démarrés, y compris celui qui contient la base de données système de pgpool-II (si le mode utilisé l'impose), avant de démarrer pgpool-II.

pgpool [-c][-f config_file][-a hba_file][-F pcp_config_file][-n][-D][-d]

-c
--clear-cache
vide le cache de requêtes
-f config_file
--config-file config-file
spécifie le fichier pgpool.conf
-a hba_file
--hba-file hba_file
spécifie le fichier pool_hba.conf
-F pcp_config_file
--pcp-password-file
spécifie le fichier pcp.conf
-n
--no-daemon
ne pas fonctionner en mode démon (le terminal n'est alors pas détaché)
-D
--discard-status
ignore le fichier de statut précédent
-d
--debug
mode de débogage
pgpool-II peut être arrêté de deux façons. La première est d'utiliser une commande PCP (détaillée plus loin dans ce document). La seconde est d'utiliser une commande pgpool-II, dont voici un exemple :

pgpool [-f config_file][-F pcp_config_file] [-m {s[mart]|f[ast]|i[mmediate]}] stop

-m s[mart]
--mode s[mart]
attends que les clients se déconnectent avant de s'arrêter (mode par défaut)
-m f[ast]
--mode f[ast]
n'attend pas la déconnexion des clients, et s'arrête immédiatement
-m i[mmediate]
--mode i[mmediate]
même chose que '-m f'

pgpool enregistre son état dans le fichier [logdir]/pgpool_status. Lorsque pgpool redémarre, il lit ce fichier et restaure le statut de chaque serveur (tel qu'il était à l'arrêt de pgpool). Cela permettra d'éviter une différence au niveau des données dans les différents nœuds PostgreSQL, qui pourrait être causée selon le scénario suivant :

  1. Un serveur s'arrête inopinément et pgpool exécute la procédure de fail-over
  2. Une mise à jour est effectuée sur l'une des bases de données actives, via pgpool
  3. L'administrateur décide d'arrêter pgpool
  4. Quelqu'un d'autre décide de redémarrer la base de données qui est en train de s'arrêter, sans en informer l'administrateur
  5. L'administrateur redémarre pgpool

Si, pour une raison quelconque, la base de données arrêtée a été synchronisée avec la base de données active d'une autre manière, pgpool_status peut alors être supprimé sereinement avant de démarrer pgpool.

Rechargement des fichiers de configuration de pgpool-II

pgpool-II peut recharger ses fichiers de configuration et se mettre alors à jour par rapport à ces derniers, sans avoir à être redémarré.

pgpool [-c][-f config_file][-a hba_file][-F pcp_config_file] reload

-f config_file
--config-file config-file
spécifie le fichier pgpool.conf
-a hba_file
--hba-file hba_file
spécifie le fichier pool_hba.conf
-F pcp_config_file
--pcp-password-file
spécifie le fichier pcp.conf

Il faut bien faire attention au fait que certains paramètres de configuration ne peuvent pas être changés par un rechargement. De plus, la nouvelle configuration ne prend effet qu'à partir des nouvelles sessions créées.

Commandes SHOW

Aperçu

pgpool-II donne quelques informations via les commandes SHOW. SHOW est une commande SQL existante, mais pgpool-II l'intercepte si la requête concerne des informations spécifiques à pgpool-II. Voici les options spécifiques à pgpool-II :

  • pool_status, pour avoir la configuration
  • pool_nodes, pour avoir des informations sur les nœuds
  • pool_processes, pour avoir l'information sur les processus de pgpool-II
  • pool_pools, pour avoir l'information sur les pools de pgpool-II
  • pool_version, pour avoir la version de pgpool-II

Note : Le terme 'pool' réfère au nombre de sessions PostgreSQL détenues par un processus pgpool, et non le nombre total de sessions détenues par pgpool.

L'option pool_status était disponible dans les versions précédentes, mais les autres sont apparues avec la version 3.0.

pool_status

"SHOW pool_status" renvoie la liste des paramètres de configuration avec leur nom, leur valeur et leur description. Voici un exemple du résultat obtenu avec cette commande :

benchs2=# show pool_status;
             item              |              value              |                           description                            
-------------------------------+---------------------------------+------------------------------------------------------------------
 listen_addresses              | 127.0.0.1                       | host name(s) or IP address(es) to listen to
 port                          | 9999                            | pgpool accepting port number
 socket_dir                    | /tmp                            | pgpool socket directory
 num_init_children             | 5                               | # of children initially pre-forked
 child_life_time               | 300                             | if idle for this seconds, child exits

pool_nodes

"SHOW pool_nodes" renvoie une liste de nœuds configurés. Il affiche l'identifiant du nœud, son nom d'hôte (ou son adresse IP), son port, son statut et le poids (qui n'a d'intérêt que si on utilise le mode de répartition de charge des requêtes en lecture). Les valeurs possibles pour la colonne status sont explicitées dans la partie dédiée à pcp_node_info.

benchs2=# show pool_nodes;
  id  |  hostname   | port | status | lb_weight     
------+-------------+------+--------+-----------
   0  | 127.0.0.1   | 5432 | 2      | 0.5
   1  | 192.168.1.7 | 5432 | 3      | 0.5
(2 lignes)

pool_processes

"SHOW pool_processes" renvoie une liste de tous les processus qui attendent une connexion ou interagissent avec une connexion.

Cette liste a 6 colonnes :

  • pool_pid est le PID du processus pgpool affiché
  • start_time est l'horodatage correspondant au démarrage du processus
  • database est le nom de la base de données où le serveur est actuellement connecté
  • username est le nom de l'utilisateur utilisé dans la connexion au serveur pour ce processus
  • create_time est l'horodatage correspondant à la création de la connexion
  • pool_counter compte le nombre de fois que ce pool de connexions (le processus) a été utilisé par les clients

Cette vue retournera toujours un nombre de lignes équivalent à num_init_children.

benchs2=# show pool_processes;
   pool_pid |     start_time      | database | username  |     create_time     | pool_counter 
----------+---------------------+----------+-----------+---------------------+--------------
 8465     | 2010-08-14 08:35:40 |          |           |                     | 
 8466     | 2010-08-14 08:35:40 | benchs   | guillaume | 2010-08-14 08:35:43 | 1
 8467     | 2010-08-14 08:35:40 |          |           |                     | 
 8468     | 2010-08-14 08:35:40 |          |           |                     | 
 8469     | 2010-08-14 08:35:40 |          |           |                     | 
(5 lines)

pool_pools

"SHOW pool_pools" renvoie une liste de pools détenus par pgpool-II, avec leurs noms, valeurs et description. Voici un exemple de résultat :

Cette liste a 11 colonnes :

  • pool_pid est le PID du processus pgpool-II
  • start_time est l'horodatage qui correspond au lancement du processus
  • pool_id est l'identifiant du pool (qui doit être entre 0 et max_pool-1)
  • backend_id est l'identifiant du serveur (qui doit être entre 0 et le nombre de serveurs configurés moins un).
  • database est le nom de la base de données utilisée dans cette connexion
  • username est le nom d'utilisateur utilisé dans cette connexion
  • create_time est l'horodatage de création de cette connexion
  • majorversion et minorversion sont les versions de protocole utilisées par cette connexion
  • pool_counter compte le nombre de fois que cette connexion a été utilisée par les clients
  • pool_backendpid et le PID du processus PostgreSQL
  • pool_connected et à vrai (1) si un client utilise actuellement cette connexion

Cette vue retournera toujours le même nombre de lignes que num_init_children * max_pool

  pool_pid |     start_time      | pool_id | backend_id | database | username  |     create_time     | majorversion | minorversion | pool_counter | pool_backendpid | pool_connected 
----------+---------------------+---------+------------+----------+-----------+---------------------+--------------+--------------+--------------+-----------------+----------------
 8465     | 2010-08-14 08:35:40 | 0       | 0          |          |           |                     |              |              |              |                 | 
 8465     | 2010-08-14 08:35:40 | 1       | 0          |          |           |                     |              |              |              |                 | 
 8465     | 2010-08-14 08:35:40 | 2       | 0          |          |           |                     |              |              |              |                 | 
 8465     | 2010-08-14 08:35:40 | 3       | 0          |          |           |                     |              |              |              |                 | 
 8466     | 2010-08-14 08:35:40 | 0       | 0          | benchs   | guillaume | 2010-08-14 08:35:43 | 3            | 0            | 1            | 8473            | 1
 8466     | 2010-08-14 08:35:40 | 1       | 0          |          |           |                     |              |              |              |                 | 
 8466     | 2010-08-14 08:35:40 | 2       | 0          |          |           |                     |              |              |              |                 | 
 8466     | 2010-08-14 08:35:40 | 3       | 0          |          |           |                     |              |              |              |                 | 
 8467     | 2010-08-14 08:35:40 | 0       | 0          |          |           |                     |              |              |              |                 | 
 8467     | 2010-08-14 08:35:40 | 1       | 0          |          |           |                     |              |              |              |                 | 
 8467     | 2010-08-14 08:35:40 | 2       | 0          |          |           |                     |              |              |              |                 | 
 8467     | 2010-08-14 08:35:40 | 3       | 0          |          |           |                     |              |              |              |                 | 
 8468     | 2010-08-14 08:35:40 | 0       | 0          |          |           |                     |              |              |              |                 | 
 8468     | 2010-08-14 08:35:40 | 1       | 0          |          |           |                     |              |              |              |                 | 
 8468     | 2010-08-14 08:35:40 | 2       | 0          |          |           |                     |              |              |              |                 | 
 8468     | 2010-08-14 08:35:40 | 3       | 0          |          |           |                     |              |              |              |                 | 
 8469     | 2010-08-14 08:35:40 | 0       | 0          |          |           |                     |              |              |              |                 | 
 8469     | 2010-08-14 08:35:40 | 1       | 0          |          |           |                     |              |              |              |                 | 
 8469     | 2010-08-14 08:35:40 | 2       | 0          |          |           |                     |              |              |              |                 | 
 8469     | 2010-08-14 08:35:40 | 3       | 0          |          |           |                     |              |              |              |                 | 
(20 lines)

pool_version

"SHOW pool_version" affiche la version de pgpool-II. En voici un exemple :

benchs2=# show pool_version;
      pool_version      
------------------------
 3.0-dev (umiyameboshi)
(1 line)

Online Recovery

Aperçu

pgpool-II, alors qu'il est en mode réplication, peut synchroniser une base de données et attacher un nœud tout en continuant à répondre aux clients. Cette fonctionnalité est appelée « online recovery ».

Le nœud cible de cette restauration doit être dans l'état détaché avant de lancer le « online recovery ». Si on veut ajouter un serveur PostgreSQL dynamiquement, ajoutez un paramètre backend_hostname et ces paramètres associés, et rechargez pgpool.conf. pgpool-II va alors enregistrer ce nouveau serveur et l'afficher dans l'état détaché.

Attention : Penser à arrêter l'autovacuum sur le nœud maître (autrement dit le premier qui est ouvert et en fonctionnement). En effet, autovacuum pourrait changer le contenu d'une base de données et alors causer une incohérence après un « online recovery ». Cela s'applique uniquement si on fait la restauration avec un mécanisme simple tel que la technique rsync détaillée plus bas. Cela ne s'applique bien sûr pas si on utilise la technique basée sur le PITR de PostgreSQL.

Si le serveur PostgreSQL a déjà été démarré, il faut l'arrêter.

pgpool-II effectue le « online recovery » en deux phase séparées. Il y a quelques secondes ou minutes pendant lesquelles un client sera en attente de connexion à pgpool-II, lorsque la restauration et la synchronisation du nœud a lieu. Ce mécanisme suit les étapes suivantes :

  1. CHECKPOINT
  2. Première phase du « online recovery »
  3. Attendre que tous les clients soient déconnectés
  4. CHECKPOINT
  5. Seconde phase du « online recovery »
  6. Démarrage du nouveau postmaster (effectué par pgpool_remote_start)
  7. Attachement du nœud

La première étape de la synchronisation des données est appelée première phase. Les données sont en effet synchronisées pendant cette étape. Pendant cette dernière, les données peuvent être mises à jour ou récupérées par les clients, sur toutes les tables, de manière concurrente.

On peut spécifier un script qui sera exécuté pendant cette première phase. pgpool-II passe alors trois arguments à ce dernier :

  1. le chemin complet vers le répertoire des données de l'instance PostgreSQL du nœud maître
  2. le nom d'hôte (ou IP) du serveur à restaurer
  3. le chemin complet vers le répertoire des données de l'instance PostgreSQL du serveur à restaurer

La synchronisation des données est finalisée dans ce qui est appelé la seconde phase. Avant d'entrer dans cette dernière, pgpool-II attend que tous les clients soient déconnectés. Il bloque alors toute nouvelle connexion jusqu'à ce que cette seconde phase soit terminée. Après que toutes les connexions soient terminées, pgpool-II applique toutes les données mises à jour pendant la première et la seconde phase sur le nœud en cours de restauration. Cela achève ainsi la dernière phase de synchronisation des données.

Il est à noter qu'il y a une restriction sur le « online recovery ». Si pgpool-II lui-même est installé sur plusieurs serveurs, le « online recovery » ne fonctionnera pas correctement car pgpool-II doit arrêter tous les clients pendant la seconde phase du « online recovery ». Ainsi, s'il y a plusieurs serveurs pgpool, un seul aura reçu la commande de « online recovery » et bloquera les connexions.

Configuration du « online recovery »

Il convient de configurer les paramètres suivants pour le « online recovery » dans le fichier pgpool.conf.

  • backend_data_directory
  • recovery_user
  • recovery_password
  • recovery_1st_stage_command
  • recovery_2nd_stage_command

Installation des fonctions en langage C

Les fonctions en langage C suivantes doivent être installées dans la base template1 de tous les serveurs PostgreSQL pour que le « online recovery » fonctionne. Leur code source est dans le répertoire suivant de l'archive de pgpool-II :

  pgpool-II-x.x.x/sql/pgpool-recovery/

Il convient de changer le nom du répertoire ci-dessus pour l'ajuster à votre version précise de pgpool-II. On se place dans ce dernier et on lance la commande « make install » :

  % cd pgpool-II-x.x.x/sql/pgpool-recovery/
  % make install

À présent, il faut installer les fonctions SQL correspondantes :

  % cd pgpool-II-x.x.x/sql/pgpool-recovery/
  % psql -f pgpool-recovery.sql template1

Déploiement du script de restauration

Des scripts de synchronisation de données doivent être déployés ainsi qu'un script qui permet de démarrer PostgreSQL à distance, et tout ceci, dans le répertoire des données de l'instance de PostgreSQL ($PGDATA). Plusieurs scripts d'exemple sont disponibles dans le répertoire pgpool-II-x.x.x/sample.

« Online recovery » grâce au PITR

Voici comment faire un « online recovery » grâce au Point In Time Recovery (PITR), qui est disponible à partir de la version 8.2 de PostgreSQL. Attention, tous les serveurs impliqués doivent avoir le PITR d'activé et correctement configuré.

Il est nécessaire d'avoir un script qui se charge d'effectuer une sauvegarde complète du serveur PostgreSQL sur un nœud maître et de l'envoyer sur un nœud cible pour la restauration lors de la première phase. Ce script peut être nommé copy-base-backup par exemple. Voici un exemple de ce script :

  #! /bin/sh
  DATA=$1
  RECOVERY_TARGET=$2
  RECOVERY_DATA=$3

  psql -c "select pg_start_backup('pgpool-recovery')" postgres
  echo "restore_command = 'scp $HOSTNAME:/data/archive_log/%f %p'" > /data/recovery.conf
  tar -C /data -zcf pgsql.tar.gz pgsql
  psql -c 'select pg_stop_backup()' postgres
  scp pgsql.tar.gz $RECOVERY_TARGET:$RECOVERY_DATA

Ce script place le serveur maître en mode sauvegarde à chaud, puis génère le fichier recovery.conf suivant :

restore_command = 'scp master:/data/archive_log/%f %p'
Ensuite, il effectue la sauvegarde, puis sort le serveur maître du mode sauvegarde à chaud et copie enfin la sauvegarde sur le nœud désiré.

La seconde phase de cette procédure est un script qui va forcer un changement de journal de transactions (XLOG). Ce script est nommé pgpool_recovery_pitr ici. Il utilise pg_switch_xlog. Cependant, il pourrait rendre la main avant que le changement de journal ne soit fait, ce qui pourrait alors provoquer un échec de la procédure d'« online recovery ». pgpool-II fournit une méthode plus sûre avec la fonction pgpool_swich_xlog, qui attend que le changement effectif de journal de transaction ait eu lieu. Cette fonction est installée avec la procédure explicitée dans la section Installation des fonctions en langage C.

Voici un script d'exemple :

#! /bin/sh
# Online recovery 2nd stage script
#
datadir=$1		  # master dabatase cluster
DEST=$2			  # hostname of the DB node to be recovered
DESTDIR=$3		  # database cluster of the DB node to be recovered
port=5432		  # PostgreSQL port number
archdir=/data/archive_log # archive log directory

# Force to flush current value of sequences to xlog 
psql -p $port -t -c 'SELECT datname FROM pg_database WHERE NOT datistemplate AND datallowconn' template1|
while read i
do
  if [ "$i" != "" ];then
    psql -p $port -c "SELECT setval(oid, nextval(oid)) FROM pg_class WHERE relkind = 'S'" $i
  fi
done

psql -p $port -c "SELECT pgpool_switch_xlog('$archdir')" template1

Cette mise à jour des séquences est uniquement utile dans le mode réplication : dans ce cas, les séquences doivent avoir le même numéro de démarrage sur tous les nœuds. Ça n'est pas utile dans le mode maître-esclave. La boucle dans ce script force PostgreSQL à émettre la valeur courante de toutes les séquences dans toutes les bases du nœud maître dans le journal de transactions afin que celles-ci soient propagées au nœud en cours de restauration.

Ces scripts doivent être déployés dans le répertoire des données de l'instance PostgreSQL (autrement dit $PGDATA).

Enfin, on édite le fichier pgpool.conf.

recovery_1st_stage_command = 'copy-base-backup'
recovery_2nd_stage_command = 'pgpool_recovery_pitr'

Cette opération termine la préparation du « online recovery » via le PITR.

pgpool_remote_start

Ce script démarre le processus postmaster sur les nœuds distants. pgpool-II l'exécute de la manière suivante.

  % pgpool_remote_start remote_host remote_datadir
  remote_host:    Nom d'hôte de la machine cible à restaurer
  remote_datadir: Chemin vers le répertoire des données de l'instance PostgreSQL sur une machine en
restauration

Dans ce script d'exemple, on démarre le processus postmaster via ssh. Afin qu'il fonctionne, on doit pouvoir se connecter via ssh sans mot de passe.

Si la restauration se fait avec PITR, il faut déployer le script de sauvegarde de base. PostgreSQL démarrera alors automatiquement en effectuant une restauration via le PITR. Il acceptera ensuite les connexions.

#! /bin/sh
DEST=$1
DESTDIR=$2
PGCTL=/usr/local/pgsql/bin/pg_ctl

# Déploiement du script de backup
ssh -T $DEST 'cd /data/; tar zxf pgsql.tar.gz' 2>/dev/null 1>/dev/null < /dev/null
# Démarrage du serveur PostgreSQL
ssh -T $DEST $PGCTL -w -D $DESTDIR start 2>/dev/null 1>/dev/null < /dev/null &

« Online recovery » avec rsync

PostgreSQL 7.4 n'a pas le PITR, qui n'est apparu qu'en version 8.0. rsync peut alors être utilisé pour effectuer le « online recovery ». Dans le script d'exemple disponible dans les sources de pgpool-II, il y a un script de restauration qui est nommé pgpool_recovery. Ce dernier utilise la commande rsync. pgpool-II appelle ce script avec trois arguments.

  % pgpool_recovery datadir remote_host remote_datadir
  datadir:        Répertoire des données de l'instance PostgreSQL sur un serveur maître
  remote_host:    Nom d'hôte (ou IP) du serveur cible à restaurer
  remote_datadir: Répertoire des données de l'instance PostgreSQL du serveur cible à
restaurer

Ce script copie les fichiers de manière physique grâce à rsync et via ssh. Comme précédemment, on doit pouvoir se connecter via ssh sans mot de passe.

Note à propos de rsync :

  • -c (ou --checksum) : cette option est requise pour assurer une transmission fiable
  • -z (ou --compress) : cette option fait de la compression des fichiers lors de leur transmission. Cela sera fort utile pour les connexions réseau lentes, mais pourrait ajouter une grosse surcharge inutile sur le CPU (à cause de la compression) pour des réseaux à 100 Mbits voire supérieurs. Dans ces derniers cas, il sera préférable de ne pas utiliser la compression.
  • rsync 3.0.5 a d'excellentes améliorations de performances en vitesse (près de 50% plus rapide d'après les discussions qui ont eu lieu sur la liste de discussion pgpool-general)

Si on utilise pgpool_recovery, il convient d'ajouter les lignes suivantes au ficher pgpool.conf :

recovery_1st_stage_command = 'pgpool_recovery'
recovery_2nd_stage_command = 'pgpool_recovery'

Comment effectuer un « online recovery »

Afin de réaliser un « online recovery », on peut utiliser la commande pcp_recovery_node ou bien pgpoolAdmin.

Il est à noter qu'on doit positionner un nombre important dans le tout premier argument de pcp_recovery_node. Il s'agit d'un délai maximum en secondes. Si on utilise pgpoolAdmin, il convient aussi de mettre un grand nombre au paramètre "_PGPOOL2_PCP_TIMEOUT" dans le fichier de configuration pgmgt.conf.php.

Que faire en cas d'erreur

Cette section décrit quelques problèmes qui peuvent survenir lors de l'utilisation de pgpool-II, ainsi que leur solutions.

    Health check failed

    pgpool-II vérifie périodiquement que tous les serveurs configurés fonctionnent correctement.

    2010-07-23 16:42:57 ERROR: pid 20031: health check failed. 1 th host foo at port 5432 is down
    2010-07-23 16:42:57 LOG:   pid 20031: set 1 th backend down status
    2010-07-23 16:42:57 LOG:   pid 20031: starting degeneration. shutdown host foo(5432)
    2010-07-23 16:42:58 LOG:   pid 20031: failover_handler: set new master node: 0
    2010-07-23 16:42:58 LOG:   pid 20031: failover done. shutdown host foo(5432)
    

    Ici, la trace montre que le serveur 1 (nom d'hôte "foo") s'arrête puis est déconnecté (shutdown) de pgpool. Ensuite, le serveur 0 devient le nouveau maître. Il convient donc de vérifier le serveur 1 et corriger la cause de l'erreur. Ensuite, il faudra effectuer un « online recovery » sur le serveur 1 si c'est possible.

    Failed to read kind from frontend

    2010-07-26 18:43:24 LOG:   pid 24161: ProcessFrontendResponse: failed to read kind from frontend. frontend abnormally exited
    

    Cette trace indique simplement que le programme client ne s'est pas connecté correctement à pgpool-II. Les causes possibles sont : un bug dans les applications clientes, la déconnexion forcée d'une application cliente (un "kill" par exemple) ou bien une erreur réseau temporaire. Ce genre d'évènements ne mène pas à la destruction d'une base de données ou même à une corruption de données. Il s'agit juste d'un avertissement sur le fait qu'il y a eu une violation du protocole utilisé par pgpool-II. Il est cependant recommandé d'investiguer plus en avant si ce message arrive trop souvent.

    Kind mismatch errors

    Cette erreur peut survenir si pgpool-II fonctionne en mode réplication.

    2010-07-22 14:18:32 ERROR: pid 9966: kind mismatch among backends. Possible last query was: "FETCH ALL FROM c;" kind details are: 0[T] 1[E: cursor "c" does not exist]
    

    pgpool-II attend les réponses des serveurs PostgreSQL après leur avoir envoyé une commande SQL. Ce message indique que tous les serveurs de données ne retournent pas le même type de réponse. La requête SQL qui a causé l'erreur se trouve après « Possible last query was: ». Ensuite, le type de réponse suit. Ici, on peut lire que « 0[T] » affiche la réponse du serveur de données: « 0[T] » (renvoi de la description de l'enregistrement), et que « 1[E » affiche que le serveur 1 retourne une erreur avec le message « cursor c does not exist », alors que le serveur 0 renvoie bien la description de l'enregistrement.

    Attention, on pourrait aussi avoir cette erreur dans le mode maître-esclave. Par exemple, même dans le mode maître-esclave, la commande SET sera envoyée à tous les serveurs de données pour qu'ils soient dans le même état.

    Il convient de vérifier alors les serveurs de données et éventuellement les resynchroniser en utilisant le « online recovery », quand c'est possible et si nécessaire.

    Pgpool detected difference of the number of inserted, updated or deleted tuples

    Dans le mode réplication, pgpool-II a détecté un nombre différent d'enregistrements mis à jour (en INSERT, UPDATE ou DELETE) sur les différents serveurs.

    2010-07-22 11:49:28 ERROR: pid 30710: pgpool detected difference of the number of inserted, updated or deleted tuples. Possible last query was: "update t1 set i = 1;"
    2010-07-22 11:49:28 LOG:   pid 30710: ReadyForQuery: Degenerate backends: 1
    2010-07-22 11:49:28 LOG:   pid 30710: ReadyForQuery: Affected tuples are: 0 1
    

    Dans l'exemple ci-dessus, le nombre d'enregistrements mis à jour grâce à « UPDATE t1 SET i = 1 » est différent à travers les différents serveurs de données. La ligne qui suit indique que le serveur 1 a été dégénéré (déconnecté) : c'est la conséquence du fait que pour le serveur 0 le nombre d'enregistrement mis à jours a été de 0, alors que pour le serveur 1 le nombre d'enregistrements modifiés a été de 1.

    Il convient alors d'arrêter le serveur que l'on suspecte être désynchronisé (ou simplement ne pas avoir les bonnes données), puis de procéder à un « online recovery ».

Restrictions

Fonctionnalités de PostgreSQL

  • Si on utilise pg_terminate_backend() pour arrêter un processus serveur PostgreSQL, cela provoquera un failover. La raison de ce comportement est que PostgreSQL envoie alors exactement le même message que si c'était le postmaster lui-même qui s'arrêtait complètement. Il n'existe pas de contournement à ce problème à ce jour. Aussi, il faut veiller à ne pas utiliser cette fonction pour le moment.

Authentification / Contrôle d'accès

  • Dans le mode réplication ou maître-esclave, les méthode d'authentification supportées sont trust, mot de passe en clair et pam. md5 est aussi supporté depuis la version 3.0 de pgpool-II. md5 est supporté en utilisant pool_passwd. Voici les étapes à respecter pour autoriser l'authentification md5 :
    1. Se connecter au système d'exploitation du serveur de données, avec l'utilisateur qui a les droits (postgres) et entrer : pg_md5 --md5auth <mot_de_passe>
      le nom d'utilisateur et son mot de passe chiffré en md5 sont alors enregistrés dans pool_passwd. Si ce dernier n'existe pas encore, la commande pg_md5 va le créer automatiquement.
    2. Le format utilisé par pool_passwd est "nom_d_utilisateur:mot_de_passe_encrypté_md5"
    3. Il faudra aussi une entrée appropriée md5 dans le fichier pool_hba.conf. À cet effet, voir Configuration de pool_hba.conf pour l'authentification des clients pour plus de détails
    4. Il faut bien veiller à ce que le nom d'utilisateur et son mot de passe soient strictement identiques à ce qui se trouvent dans le serveur PostgreSQL pour que cela fonctionne
  • Dans tous les autres modes, les méthodes trust, mot de passe en clair, crypt, md5 et pam sont supportées.
  • pgpool-II ne supporte pas les contrôles d'accès comme pg_hba.conf de PostgreSQL. Par exemple, si les connexions TCP/IP sont activées, pgpool-II accepte toutes les connexions TCP/IP, quel que soient leurs origines. Si c'est absolument requis dans le contexte, il convient d'utiliser un programme comme iptables afin de contrôler les accès TCP/IP. Bien sûr, les serveurs PostgreSQL qui acceptent les connexions pgpool-II peuvent utiliser leur configuration pg_hba.conf propre.

Large objects

pgpool-II 2.3.2 et suivants supportent la réplication des « large objects » si le serveur PostgreSQL est au moins en version 8.1. Pour que cela fonctionne, il faut activer la directive de configuration lobj_lock_table dans le fichier pgpool.conf. Cependant, la réplication des « large objects » utilisant la fonction PostgreSQL lo_import n'est pas supportée.

Tables temporaires en mode maître-esclave

Tout ce qui concerne les tables temporaires est toujours exécuté sur le maître. À partir de la version 3.0 de pgpool-II, les SELECT sur ces tables sont eux-aussi exécutés sur le maître. Cependant, si le nom de la table temporaire est utilisé comme un littéral dans le SELECT, il n'y a aucun moyen de le détecter. Du coup, les SELECT seront répartis entre les serveurs PostgreSQL. Cela amènera à une erreur, la table n'existant que sur le maître ("not found the table..."). Pour éviter ce problème, il faut utiliser le commentaire « /*NO LOAD BALANCE*/ » dans le corps de la requête SQL contenant l'appel en SELECT sur la table temporaire.

Voici en uxemple de SELECT qui pose problème :
SELECT 't1'::regclass::oid;

La commande "\d" de psql utilise les tables de nom en littéral. À partir de la version 3.0 de pgpool-II, ce dernier va tester si le SELECT contient un accès au catalogue système et enverra alors les requêtes au maître dans l'affirmative. Cela permet de contourner le problème.

Fonctions et autres en mode réplication

Il n'y a aucune garantie que toute donnée obtenue via un mécanisme dépendant du contexte (par exemple un nombre au hasard, un numéro de transaction, un OID, un SERIAL ou une sequence) sera répliquée correctement sur plusieurs serveurs PostgreSQL.

Pour SERIAL, l'activation de la directive de configuration insert_lock permettra de répliquer correctement la donnée. Cela permettra aussi un bon fonctionnement de "SELECT setval()" et "SELECT nextval()".

À partir de la version 2.3 de pgpool, les INSERT et UPDATE qui utilisent CURRENT_TIMESTAMP, CURRENT_DATE et now() seront répliqués correctement. De même, les INSERT et UPDATE pour les tables qui utilisent CURRENT_TIMESTAMP, CURRENT_DATE et now() comme leur valeur par défaut (DEFAULT valeur) seront aussi répliqués correctement. Cela est obtenu en remplaçant ces fonctions par des constantes qui sont récupérées sur le maître au moment de l'exécution de la requête. Il y a cependant quelques limitations :

  • Le calcul de la donnée temporelle n'est pas correct dans quelques cas. Par exemple, voici une définition de table :
    CREATE TABLE rel1(
      d1 date DEFAULT CURRENT_DATE + 1
    )
    
    Ceci est traité de la même façon que :
    CREATE TABLE rel1(
      d1 date DEFAULT CURRENT_DATE
    )
    

    Il est à noter que si le type de la colonne n'est pas temporel, la réécriture n'est pas effectuée. En voici un exemple :

    foo bigint default (date_part('epoch'::text,('now'::text)::timestamp(3) with time zone) * (1000)::double precision)
    

  • Supposons à présent que nous ayons la table suivante :
    CREATE TABLE rel1(
      c1 int,
      c2 timestamp default now()
    )
    
    On peut répliquer :
    INSERT INTO rel1(c1) VALUES(1) 
    
    puis que cela se transforme en :
    INSERT INTO rel1(c1, c2) VALUES(1, '2009-01-01 23:59:59.123456+09')
    
    Cependant :
    INSERT INTO rel1(c1) SELECT 1
    
    ne peut pas être transformé. Il ne sera donc pas correctement répliqué avec l'implémentation actuelle. Les valeurs seront cependant insérées, mais sans aucune transformation.

Les tables créées avec CREATE TEMP TABLE seront supprimées à la fin de la session en spécifiant DISCARD ALL dans le paramètre de configuration reset_query_list si on utilise la version 8.3 ou supérieure de PostgreSQL.

Pour les version 8.2.X et précédentes, CREATE TEMP TABLE ne sera pas supprimé à la sortie de la session. Ceci est dû au pooling de connexion, qui, du point de vue du serveur PostgreSQL, garde la session en vie. Pour éviter cela, on doit supprimer explicitement la table dans le bloc de transaction, soit en ajoutant un DROP TABLE, soit en créant la table temporaire avec CREATE TEMP TABLE ... ON COMMIT DROP.

Requêtes

Voici les requêtes qui ne peuvent pas être traitées par pgpool-II :

INSERT (en mode parallèle)

On ne peut pas utiliser DEFAULT avec la colonne qui sert de clé de partitionnement. Par exemple, si la colonne x dans la table t est la colonne qui sert de clé de partitionnement :

INSERT INTO t(x) VALUES (DEFAULT);

est invalide. De même, les fonctions ne peuvent pas être utilisées pour cette valeur non plus.

INSERT INTO t(x) VALUES (func());

Les valeurs constantes doivent être utilisées pour un INSERT avec la clé de partitionnement. SELECT INTO et INSERT INTO ... SELECT ne sont pas supportés non plus.

UPDATE (en mode parallèle)

La cohérence des données entre les serveurs pourrait être perdue si la colonne qui sert de clé de partitionnement subit des mises à jour. En effet, pgpool-II ne re-partitionne pas les données ainsi mises à jour.

Une transaction ne peut pas être annulée (ROLLBACK) si la requête qui a causé l'erreur sur un ou plusieurs serveurs PostgreSQL est due à une violation de contrainte.

Si une fonction est appelée dans la clause WHERE, la requête pourrait ne pas être correctement exécutée. Par exemple :

UPDATE branches set bid = 100 where bid = (select max(bid) from beances);

SELECT ... FOR UPDATE (en mode parallèle)

Si une fonction est appelée dans la clause WHERE, la requête pourrait ne pas être correctement exécutée. Par exemple :

SELECT * FROM  branches where bid = (select max(bid) from beances) FOR UPDATE;

COPY (en mode parallèle)

COPY BINARY n'est pas supporté. COPY à partir de fichiers n'est pas non plus supporté. Seuls COPY FROM STDIN et COPY TO STDOUT sont supportés.

ALTER/CREATE TABLE (en mode parallèle)

Pour mettre à jour une règle de partitionnement, pgpool-II doit être redémarré pour qu'il puisse relire les règles dans sa base de données système.

Transactions (en mode parallèle)

Les requêtes SELECT exécutées à l'intérieur d'un bloc de transactions seront exécutés dans des transactions séparées. Voici un exemple :

BEGIN;
INSERT INTO t(a) VALUES (1);
SELECT * FROM t ORDER BY a; << l'INSERT ci-dessus n'est pas visible pour
                               cette requête SELECT
END;

Vues et règles (en mode parallèle)

La même définition de vue ou de règle (RULE) sera créée sur tous les serveurs.

SELECT * FROM a, b where a.i = b.i

Les jointures comme celles ci-dessus seront exécutées sur chaque serveur, et le résultat de chaque serveur sera intégré pour être retourné au client. Les vues et règles ne peuvent pas faire de jointures à travers les différents serveurs. Cependant, pour faire une jointure entre des tables dont les données sont présentes sur un même serveur, une vue peut être utilisée. Cette vue doit être enregistrée dans la table du catalogue pgpool_catalog.dist_def. De même, un col_name et un dist_def_func devront être enregistrés. Ces derniers sont utilisés lors qu'une insertion est réalisée sur la vue.

Fonctions et triggers (en mode parallèle)

Pour les fonctions, c'est la même définition qui sera utilisée pour leur création dans les différents serveurs de données. Comme précédemment, on ne peut pas faire de jointure entre les différents serveurs au sein d'une fonction.

Protocole étendu de requêtage (en mode parallèle)

Le protocole étendu de requêtage (« extended query protocol ») utilisé par les connecteurs JDBC, entre autres, n'est pas supporté. Le protocole simple doit être utilisé à la place. Cela veut dire, entre autres, qu'on ne peut pas utiliser les requêtes préparées.

Jointure naturelle (en mode parallèle)

Ce n'est pas supporté non plus. Les clauses ON et USING doivent être utilisées à la place.

Clause USING (en mode parallèle)

La clause USING est convertie en une clause ON par le processus qui réécrit les requêtes. Ainsi, lorsque * est utilisé comme liste cible, les colonnes jointes apparaissent deux fois.

Voici un exemple :

  =# SELECT * FROM t1 JOIN t2 USING(id);
   id |  t  |   t
  ----+-----+-------
    1 | 1st | first
  (1 row)

Le processus de réécriture de requêtes va réécrire USING en ON. Le résultat est alors :

  =# SELECT * FROM t1 JOIN t2 ON t1.id = t2.id;
   id |  t  | id |   t
  ----+-----+----+-------
    1 | 1st |  1 | first
  (1 row)

On remarque que la colonne t est dupliquée.

Caractères multi-octets (pour tous les modes)

pgpool-II n'opère pas de traduction entre les différents caractères multi-octets. L'encodage utilisé par le client, le serveur et la base de données système doit donc être identique.

Requêtes multiples (tous modes)

pgpool-II ne peut pas prendre en charge les requêtes multiples (plusieurs requêtes séparées par un point-virgule, exécutées en un coup).

Deadlocks (en mode parallèle)

Les deadlocks à travers plusieurs serveurs ne peuvent pas être détectés. Par exemple :

(la table "tellers" est partitionnée avec la règle suivante)
  tid <= 10  --> node 0
  tid >= 10  --> node 1

A) BEGIN;
B) BEGIN;
A) SELECT * FROM tellers WHERE tid = 11 FOR UPDATE;
B) SELECT * FROM tellers WHERE tid = 1 FOR UPDATE;
A) SELECT * FROM tellers WHERE tid = 1 FOR UPDATE;
B) SELECT * FROM tellers WHERE tid = 11 FOR UPDATE;

Dans le cas ci-dessus, un serveur seul ne peut pas détecter de deadlock. Du coup, pgpool-II attendra une réponse indéfiniment. Ce phénomène peut apparaître avec toute requête qui acquiert un verrou au niveau de l'enregistrement.

Aussi, si un deadlock arrive sur un serveur, l'état de la transaction sur chaque serveur ne sera pas cohérent. Ainsi, pgpool-II arrête le processus si un deadlock est détecté.

pool_read_kind: kind does not match between master(84) slot[1] (69)

Schémas (en mode parallèle)

Les objets qui se trouve dans un autre schéma que public doivent être préfixés par le nom du schéma dans lequel ils se trouvent :

schéma.objet

pgpool-II ne peut pas résoudre le nom de schéma correct lorsque le chemin est configuré comme suit :

set search_path = xxx

et que le nom du schéma n'est pas précisé dans la requête.

nom de table - nom de colonne (en mode parallèle)

Une table ou un nom de colonne ne peut pas être préfixé par « pool_ ». En effet, lors de la réécriture des requêtes, ces noms sont utilisés par des processus internes à pgpool-II.

Base de données système

Règles de partitionnement

On ne peut définir qu'une seule clé de partitionnement par règle de partitionnement. Les condition comme « x ou y » ne sont pas supportées.

Pré-requis de l'environnement

libpq

La bibliothèque libpq est liée lors de la compilation de pgpool-II. La version de la libpq doit être la 3.0. Toute tentative de compilation de pgpool-II avec la version 2.0 de la libpq finira par un échec. De même, la base de données système doit être au minimum dans une version 7.4 de PostgreSQL.

Cache de requêtes

Actuellement, le cache de requêtes doit être supprimé manuellement. pgpool-II n'a pas de mécanisme d'invalidation de cache automatique lorsque les données sont mises à jour.

Compatibilité avec pgpool

Référence

Référence des commandes PCP

Liste des commandes PCP

Les commandes PCP sont des commandes UNIX qui interagissent avec pgpool-II à travers le réseau.

* pcp_node_count    - retourne le nombre de nœuds (serveurs PostgreSQL)
* pcp_node_info     - retourne l'information sur un nœud
* pcp_proc_count    - retourne la liste des processus
* pcp_proc_info     - retourne l'information sur un processus
* pcp_systemdb_info - retourne l'information sur la base de donnée système
* pcp_detach_node   - détache un nœud de pgpool-II
* pcp_attach_node   - attache un nœud à pgpool-II
* pcp_stop_pgpool   - stoppe pgpool-II

Arguments communs aux outils en ligne de commande

Il y a cinq arguments qui sont communs à toutes les commandes PCP. Ils donnent l'information relative à l'authentification et à pgpool-II. Des arguments complémentaires peuvent être nécessaires pour quelques commandes.

$ pcp_node_count 10 localhost 9898 postgres hogehoge

1er argument  - délai maximum en secondes (PCP se déconnecte si 
                pgpool-II ne répond pas dans le temps imparti ici)
2nd argument  - nom d'hôte (ou adresse IP) du serveur pgpool-II
3ème argument - numéro de port de PCP
4ème argument - nom d'utilisateur de PCP
5ème argument - mot de passe de l'utilisateur de PCP

Les noms d'utilisateurs et mot de passe PCP doivent être déclarés dans le fichier pcp.conf installé dans le répertoire $prefix/etc. L'option -F peut être utilisée lors du démarrage de pgpool-II si le fichier pcp.conf est placé ailleurs. Les mots de passe n'ont pas besoin d'être au format md5 lorsqu'on les passe aux commandes PCP.

Commandes PCP

Toutes les commandes PCP renvoie les résultats vers la sortie standard.

pcp_node_count

Format :
pcp_node_count  _timeout_  _hôte_  _port_  _userid_ _passwd_

Affiche le nombre total de nœuds définis dans le fichier pgpool.conf. Il ne fait aucune distinction entre le statut des différents nœuds. Ainsi, tous les nœuds sont comptés ici.

pcp_node_info

Format :
pcp_node_info  _timeout_  _hôte_  _port_  _userid_  _passwd_  _nodeid_

Affiche l'information relative au numéro de nœud donné. Voici un exemple de sortie :

$ pcp_node_info 10 localhost 9898 postgres hogehoge 0
host1 5432 1 1073741823.500000

Le résultat est dans l'ordre suivant:
1. nom d'hôte
2. numéro de port
3. statut
4. poids configuré pour la répartition de charge

Le statut est représenté par un chiffre de 0 à 3 :

0 - Cet état est uniquement utilisé pendant l'initialisation. PCP ne l'affichera jamais
1 - Le nœud est en ligne, mais aucune connexion n'est encore faite dessus
2 - Le nœud est en ligne, et les connexions sont poolés
3 - Le nœud est arrêté 

Le poids configuré pour la répartition de charge est affiché dans un format normalisé.

L'option --verbose peut permettre une meilleure compréhension. Par exemple :

$ pcp_node_info --verbose 10 localhost 9898 postgres hogehoge 0
Hostname: host1
Port    : 5432
Status  : 1
Weight  : 0.5

La spécification d'un identifiant de nœud invalide résultera dans une erreur avec un code de sortie 12, et « BackendError » sera alors affiché.

pcp_proc_count

Format :
pcp_proc_count  _timeout_  _host_  _port_  _userid_  _passwd_

Liste les identifiants des processus fils de pgpool-II. S'il y a plus d'un processus, les identifiants seront délimités par un espace.

pcp_proc_info

Format:
pcp_proc_info  _timeout_  _host_  _port_  _userid_  _passwd_  _processid_

Affiche l'information d'un processus fils de pgpool-II, désigné par son identifiant de processus. Voici un exemple de retour de cette commande :

$ pcp_proc_info 10 localhost 9898 postgres hogehoge 3815
postgres_db postgres 1150769932 1150767351 3 0 1 1467 1
postgres_db postgres 1150769932 1150767351 3 0 1 1468 1

Le résultat est affiché dans l'ordre suivant :
1. nom de la base de données connectée
2. nom de l'utilisateur connecté
3. horodatage correspondant au démarrage du processus
4. horodatage correspondant au démarrage de la connexion
5. numéro de version majeure du protocole
6. numéro de version mineure du protocole
7. compteur du nombre de réutilisations de cette connexion
8. numéro d'identifiant du processus serveur PostgreSQL
9. 1 si le client est connecté, 0 sinon

S'il n'y a aucune connexion aux processus serveurs, rien ne sera affiché. S'il y a plusieurs connexions, les informations seront affichées sur plusieurs lignes et plusieurs fois. Les horodatages sont affichés au format EPOCH.

L'option --verbose permet de mieux comprendre la sortie de la commande. Par exemple :

$ pcp_proc_info --verbose 10 localhost 9898 postgres hogehoge 3815
Database     : postgres_db
Username     : postgres
Start time   : 1150769932
Creation time: 1150767351
Major        : 3
Minor        : 0
Counter      : 1
PID          : 1467
Connected    : 1
Database     : postgres_db
Username     : postgres
Start time   : 1150769932
Creation time: 1150767351
Major        : 3
Minor        : 0
Counter      : 1
PID          : 1468
Connected    : 1

La spécification d'un identifiant de nœud invalide résultera dans une erreur avec un code de sortie 12, et « BackendError » sera alors affiché.

pcp_systemdb_info

Format :
pcp_systemdb_info  _timeout_  _host_  _port_  _userid_  _passwd_

Affiche des informations sur la base de données système. Voici un exemple de sortie :

$ pcp_systemdb_info 10 localhost 9898 postgres hogehoge
localhost 5432 yamaguti '' pgpool_catalog pgpool 3
yamaguti public accounts aid 4 aid bid abalance filler integer integer integer character(84) dist_def_accounts
yamaguti public branches bid 3 bid bbalance filler integer integer character(84) dist_def_branches
yamaguti public tellers bid 4 tid bid tbalance filler integer integer integer character(84) dist_def_tellers

L'information sur la base de donnée système sera affichée sur la toute première
ligne. Voici l'ordre des résultats :

1. nom d'hôte
2. numéro de port
3. nom d'utilisateur
4. mot de passe (une chaîne vide s'il n'y en a pas)
5. nom de schéma
6. nom de la base de données
7. nombre de règles de partitionnement définies

Ensuite, les règles de partitionnement sont affichées sur les lignes suivantes. S'il y a de multiples définitions, elles seront affichées sur autant de lignes que nécessaire. Le résultat s'affiche dans l'ordre suivant :

1. le nom de la base de données cible du partitionnement
2. le nom du schéma dans cette base
3. le nom de la table dans ce schéma
4. le nom de la colonne qui sert de clé de partitionnement
5. le nombre de colonnes dans la table
6. le nom de ces colonnes (autant de fois que précisé au 5.)
7. le nom des types de données de ces colonnes (autant de fois que précisé au 5.)
8. le nom de la fonction utilisée pour la règle de partitionnement

Si la base de données système n'est pas définie (autrement dit, on n'est pas dans un mode pgpool-II, et le cache de requêtes est désactivé), on a une erreur avec un statut de sortie à 12, et le message « BackendError » est affiché.

pcp_detach_node

Format :
pcp_detach_node  [-g] _timeout_  _host_  _port_  _userid_  _passwd_  _nodeid_

Détache le nœud spécifié de pgpool-II. Si l'option -g est donnée, la commande attend que tous les clients soient déconnectés (à moins que le paramètre client_idle_limit_in_recovery soit configuré à -1 ou que le paramètre recovery_timeout soit expiré).

pcp_attach_node

Format :
pcp_attach_node  _timeout_  _host_  _port_  _userid_  _passwd_  _nodeid_

Attache le nœud spécifié à pgpool-II.

pcp_stop_pgpool

Format :
pcp_stop_pgpool  _timeout_  _host_  _port_  _userid_  _passwd_  _mode_

Arrête le processus pgpool-II dans le mode d'arrêt spécifié. Les différents modes d'arrêt sont les suivants :

s	- mode intelligent
f	- mode rapide
i	- mode immédiat

Si le processus pgpool-II n'existe pas, on a une erreur avec un statut de sortie à 8, et le message « ConnectionError » sera affiché.

En fait, il n'y a pas de différence entre les modes rapide et immédiat. pgpool-II arrête tous les processus, qu'il y ait des clients connectés aux processus serveurs ou pas.

Statuts de sortie

Les commandes PCP on un code de sortie à 0 lorsque tout se passe bien. Si une erreur arrive, ces dernières ont un code de sortie différent, dont voici la liste :

UNKNOWNERR      1      Erreur inconnue (ne devrait pas arriver)
EOFERR          2      Erreur de fin de fichier
NOMEMERR        3      Erreur liée à une insuffisance de mémoire disponible
READERR         4      Erreur alors qu'une lecture sur le serveur était en cours
WRITEERR        5      Erreur alors qu'une écriture sur le serveur était en cours
TIMEOUTERR      6      Timeout
INVALERR        7      Les arguments passés à une commande PCP sont invalides
CONNERR         8      Erreur de connexion au serveur
NOCONNERR       9      Aucune connexion n'existe
SOCKERR         10     Erreur de socket unix
HOSTERR         11     Erreur de résolution de nom d'hôte
BACKENDERR      12     Erreur sur le processus PCP sur le serveur 
AUTHERR         13     Erreur d'autorisation

Fonctionnement interne

La version 2.0 de pgpool-II amène de nombreuses améliorations, en comparaison à la version 1. Attention, ce qui suit ne s'applique pas à la version 1.

Moteur d'exécution parallèle

Le moteur d'exécution parallèle est implémenté dans pgpool-II. Ce moteur exécute la même requête sur tous les nœuds, et pilote le moteur qui transmet les résultats au client, en fonction de la réponse des différents nœuds.

Réécriture de requêtes

Cette partie explique le fonctionnement de la réécriture de requêtes que fait pgpool-II en mode parallèle.

En mode parallèle, une requête transmise par les clients passe par deux étapes de traitements :

  • analyse de la requête ;
  • réécriture de la requête ;

Ce qui suit détaille ces deux étapes.

Analyse de la requête

Introduction

La récupération de la requête soumise par le client passe par l'analyseur SQL. Elle est alors analysée grâce aux informations stockées dans la base de données système. Le statut d'exécution stocke alors sur quel(s) nœud(s) la requête peut être traitée. Par exemple, si les données d'une table sont distribuées sur plusieurs serveurs (comme déclaré dans la table pgpool_catalog.dist_def du catalogue), ces dernières doivent être récupérées de plusieurs serveurs. Ainsi, cette étape retourne le statut P lors que les données doivent être récupérées sur tous les serveurs, L quand elles peuvent être récupérées sur un seul serveur. Le statut spécial S intervient dans un cas particulier : ce dernier signifie qu'il doit y avoir au moins une autre étape exécutée avant de pouvoir récupérer les données de tous les serveurs. Par exemple, trier les données en provenance d'une table enregistrée dans la table catalogue pgpool_catalog.dist_def.

La requête est analysée dans l'ordre suivant, et son statut d'exécution change alors au cours de cette analyse. Comment et où sera exécutée la requête dépend du statut final de la requête principale.

  1. Est-ce que UNION, EXTRACT ou INTERSECT sont utilisées ?
  2. Quel est le statut d'exécution de la clause FROM ?
  3. Changer le statut d'exécution par TARGETLIST
  4. Changer le statut d'exécution en fonction de la clause WHERE
  5. Changer le statut d'exécution en fonction de la clause GROUP BY
  6. Changer le statut d'exécution en fonction de la clause HAVING
  7. Changer le statut d'exécution en fonction de la clause ORDER BY
  8. Changer le statut d'exécution en fonction du prédicat LIMIT OFFSET
  9. Acquisition du statut final d'exécution du SELECT

La relation entre le statut d'exécution final du SELECT et l'endroit où il est exécuté est comme suit :

Statut d'exécutionLieu d'exécution
LLa requête peut-être exécutée sur n'importe quel serveur
PRetourne les données au client en exécutant la même requête sur tous les serveurs en utilisant le moteur d'exécution en parallèle.
SAprès traitement dans la base de données système, les données sont renvoyées au client.

Ces règles s'appliquent aussi aux sous-requêtes. Dans l'exemple simple ci-dessous, si la table P1-table est enregistrée dans la table catalogue pgpool_catalog.dist_def sur la base de données système (P1-table est alors distribuée), le statut d'exécution final de la sous-requête est alors P, et comme résultat, la requête parent du SELECT devient alors obligatoirement P.

SELECT * FROM (SELECT * FROM P1-table) as P2-table;

Il convient d'expliquer à présent comment le statut d'exécution change concrètement. Commençons par un exemple simple, pour expliquer le statut lié à la clause FROM.

Statut d'exécution de la clause FROM

Ceci est une requête qui récupère des données (SELECT). L'ensemble de données et son statut (P, L et S) sont définis en fonction de la clause FROM. Le statut d'exécution de la table est comme suit : lorsqu'il n'y a qu'une seule table dans la clause FROM, le statut d'exécution de l'ensemble de données entier est le même que celui de cette table. Lorsqu'il y a deux ou plusieurs tables ou des sous-requêtes dans la clause FROM, l'exécution est décidée en fonction de la méthode de jointure et des statuts d'exécutions, comme précisé dans la table suivante.

Type de jointure LEFT OUTER JOIN RIGHT OUTER JOIN FULL OUTER JOINOther
left/right P L S P L S P L S P L S
P S P S S S S S S S S P S
L S L S P L S S L S P L S
S S S S S S S S S S S S S

Dans les exemple suivants, la table P1-table est en statut P. Les tables L1-table et L2-table sont dans le statut L.

SELECT * FROM P1-table,L1-table,L2-table;
P1-table (gauche) et L1-table (droite) sont jointes, et en fonction du tableau ci-dessus, prennent le statut P. Avec ce statut P, elles sont jointes avec la table L2-table, qui est de statut L et qui devient alors en statut P aussi.

Changement de statut d'exécution dus aux clause TARGETLIST et WHERE

Dans une requête simple, le statut d'exécution est le même que celui de la clause FROM. Cependant, s'il y a une TARGETLIST, le statut d'exécution de la clause WHERE peut changer dans les cas suivants :

  1. lorsqu'il y a une sous-requête 
  2. lorsqu'il y a une fonction d'agrégat ou un DISTINCT dans la TARGETLIST marquée P 
  3. lorsqu'une colonne qui n'existe pas dans la table (l'ensemble de données) est utilisée dans la clause FROM.

Dans ces cas, le statut d'exécution final de la sous-requête, le statut d'exécution de la TARGETLIST et la clause WHERE passent en statut S si leur statut initial était P ou S.

Dans l'exemple suivant, lorsqu'une table de statut P est utilisée par une sous-requête, le statut d'exécution final de la sous-requête prend le statut P. Ainsi, le statut d'exécution de la clause WHERE passe au statut S, quel que soit le statut d'exécution de LA, et cette requête est exécutée dans la base de données système.

	SELECT * FROM L1-table where L1-table.column IN (SELECT * FROM P1-table);

La clause FROM passe au statut S lorsqu'il y a une fonction d'agrégat marquée P dans la TARGETLIST, afin de faire cet agrégat après que toutes les données aient été récupérées. Certaines optimisations sur la fonction d'agrégat sont faites dans des cas spécifiques.

Une colonne qui n'existe pas dans la table peut être utilisée dans la requête. Par exemple, dans une sous-requête corrélée :

	SELECT * FROM L1-table WHERE L1-table.col1 IN (SELECT * FROM
P1-table WHERE P1-table.col = L1-table.col1);

Cette sous-requête fait référence à L1-table.col1, dans la table L1-table. Le statut d'exécution de la clause WHERE de la sous-requête est S.

Changement de statuts d'exécution provoqués par GROUP BY, HAVING, ORDER BY et LIMIT/OFFSET

Le statut d'exécution de la cause WHERE est changé à S lorsqu'il y a une clause GROUP BY, HAVING, ORDER BY ou bien un prédicat LIMIT/OFFSET avec un statut P. Une requête sans la clause GROUP BY prend le statut d'exécution de la clause WHERE. De même, le statut d'exécution de la clause GROUP BY est utilisé lorsqu'il n'y a pas de clause HAVING. La clause ORDER BY et le prédicat LIMIT/OFFSET ont aussi le même comportement.

Lorsque UNION, EXTRACT et INTERSECT sont utilisés

Le statut des requêtes avec UNION, EXTRACT, ou INTERSECT dépend des deux statuts d'exécution finaux des requêtes gauche et droite à la fois. Si les deux sont en P et que la requête est un UNION ALL, le statut d'exécution combiné est P. Dans toutes les autres combinaisons, le statut final sera S.

Acquisition du statut d'exécution final d'une requête SELECT

Si tout ce qui est dans le SELECT est de statut L, alors le statut d'exécution final est L. La même règle s'applique pour P. Pour toutes les autres combinaisons, le statut final est S. Si le statut est L, la charge est distribuée sur tous les serveurs lorsque le paramètre loadbalance_mode vaut true, sinon elle est envoyée sur le maître (false). Pour P, un traitement parallèle est fait grâce au moteur d'exécution parallèle. Pour S, la réécriture de la requête est présentée ci-dessous est effectuée.

Réécriture de requête

La requête est réécrite ou pas en fonction de son statut d'exécution qui est acquis lors de l'analyse de la requête. Voici un exemple. La table P1-table est de statut P, la table L1-table est elle de statut L.

SELECT P1-table.col, L1-table.col 
FROM P1-table,L1-table 
WHERE P1-table.col = L1-table.col 
ORDER BY P1-table.col;

Dans cette requête, le statut est S à cause de la clause ORDER BY. Les clauses FROM, WHERE et TARGETLIST sont de statut P. La requête est alors réécrite en quelque chose ressemblant à ceci :

SELECT P1-table.col, L1-table.col FROM
	dblink(select pool_parallel(SELECT P1-table.col, L1-table.col FROM P1-table,L1-table where P1-table.col = L1-table.col)) 
  	ORDER BY P1-table.col;

dblink transmet ici la requête à pgpool-II. La fonction pool_parallel a la responsabilité de transmettre la requête au moteur d'exécution parallèle.

Dans cet exemple, les clauses FROM et WHERE, ainsi que la TARGETLIST, sont exécutés en mode parallèle. Ceci n'est pas la requête réellement réécrite, mais juste fournie en guise d'exemple, par soucis de lisibilité et de compréhension.

Voici un autre cas :

SELECT L1-table.col FROM L1-table WHERE L1-table.col % 2 = 0 AND L1-table.col IN (SELECT P1-table FROM P1-table) ;

Dans cet exemple, les clauses FROM, WHERE et la TARGETLIST sont en statut L, à cause de la sous-requête qui est de statut P. La requête elle-même est de statut S. En conséquence, une réécrite est effectuée comme suit :

	SELECT L1-table.col 
	  FROM dblink(SELECT loadbalance(SELECT L1-table.col 
	              FROM L1-table 
	              WHERE L1-table.col % 2 = 0 
	                AND TRUE))
		WHERE
			L1-table.col %2 = 0 AND 
		  L1-table.col IN 
		  (
		  	SELECT P1-Table FROM 
		  	dblink(select pool_parallel(SELECT P1-table FROM P1-table))
		  ) ;

La fonction pool_loadbalance a la responsabilité de répartir les requêtes sur les différents nœuds.

Réécriture de requêtes pour les fonctions d'agrégat

Pour les requêtes d'agrégation (fonctions d'agrégat ainsi que GROUP BY), le mécanisme de réécriture tente de réduire la charge sur la base de données système en exécutant un premier agrégat sur chacun des serveurs.

Voyons tout d'abord comment pgpool-II fait cette réécriture.

Cette requête est en statut P dans la clause FROM et possède un count(*) dans la TARGETLIST. Aussi, la réécriture est faite comme suit.

  SELECT count(*) from P1-table;

	-> réécriture

    SELECT
        sum(pool_c$1) AS count
    FROM
        dblink(select pool_parallel('SELECT count(*) FROM  P1-table'))
					AS pool_$1g (pool_c$1 bigint);

Une réécriture comme ci-dessus est faite dans les conditions suivantes.

  1. la clause FROM est de statut P ;
  2. la colonne spécifiée est dans la fonction d'agrégat (seulement COUNT, SUM, MIN, MAX et AVG) et GROUP BY est utilisé dans la TARGETLIST ;
  3. la clause WHERE est de statut P ;
  4. seules les colonnes définies dans la fonction d'agrégat (seulement COUNT, SUM, MIN, MAX et AVG), utilisées dans la clause HAVING et la clause FROM, et la colonne spécifiée pour le GROUP BY sont utilisées.

Notes sur le mode parallèle

Le nom des colonnes et leur type de données doivent être connus lorsqu'une requête est analysée en mode parallèle. Ainsi, lorsqu'une expression ou une fonction est utilisée dans la TARGETLIST d'une sous-requête, l'alias et le type (via un CAST) sont nécessaires. Si aucun cast n'est défini explicitement dans une expression ou une fonction, le type TEXT sera choisi par défaut. Pour count(), le type BIGINT est celui par défaut, et pour sum(), NUMERIC. Pour min()/max(), si l'argument est de type DATE, le type de données retournée est DATE, sinon NUMERIC est utilisé. avg() est traité comme sum()/count() (sum divisé par count).

À propos des performances du mode parallèle

Voici une estimation des performances de la requête en fonction de son statut d'exécution

Statut d'exécutionPerformances
LIl n'y a aucune déterioration de performance avec un unique serveur, mis à part la sucharge provoquée par pgpool-II, parce qu'aucune exécution en parallèle n'est possible.
PLe traitement parallélisé est rapide, en particulier, pour les parcours séquentiels. Il est alors aisé d'avoir de grandes améliorations de performances car le parcours séquentiel d'une grosse table devient un parcours en parallèle sur des tables bien plus petites, distribuées sur plusieurs serveurs.
SLorsque les fonctions d'agrégat peuvent être réécrites pour être compatibles avec une exécution en parallèle, elles deviennent rapides.

Tutoriel

Un tutoriel (en anglais) pour pgpool-II est disponible.