Aller au contenu

Pgpool-II

Fonctionnalités

  • Répartition automatique des requêtes entre le maître et le ou les esclaves (suivant qu’elles sont en lecture seule ou lecture-écriture)
  • Bascule automatique du maître vers un des esclaves
  • Réplication entre bases par réplication des ordres SQL
  • Cache de résultat des requêtes

Sur le papier, l’utilisation de Pgpool-II est une bonne idée, car il est présenté comme répondant à ces problématiques.

Problèmes

  • Pgpool-II permet la répartition de charge entre les serveurs PostgreSQL. Mais :
  • Il nécessite l’utilisation de listes noires (blacklists) de fonctions réalisant des mises à jour en base, afin que toute requête utilisant ces fonctions soit bien envoyée vers le serveur maître. Cette blacklist est donc à entretenir en plus du code applicatif. On peut aussi s’en sortir en mettant des «hints» sur les requêtes, c’est-à-dire des commentaires empêchant Pgpool-II de renvoyer ces requêtes sur un esclave, ce qui est tout aussi fragile.
  • Il peut renvoyer vers un esclave des requêtes qui, malgré qu’elles soient en lecture, doivent être exécutées sur le maître. Un esclave est toujours en retard sur le maître, même quand c’est un esclave synchrone : c’est la réplication des données qui est synchrone, pas leur visibilité sur l’esclave. Ce dernier point n’est plus tout à fait exact à partir de PostgreSQL 9.6 : on peut paramétrer la réplication synchrone en mode remote_apply. C’est toutefois une fausse bonne idée : on va pénaliser encore plus fortement le maître, qui est probablement déjà le goulet d’étranglement de l’infrastructure. Pgpool-II peut donc envoyer de lui-même une requête sur un esclave qui a besoin de données à jour. Nous avons déjà été confrontés à cette problématique : l’application peut créer un enregistrement (cela sera envoyé sur le maître), puis le consulter dans une transaction ultérieure (qui pourra être envoyée sur l’esclave). L’enregistrement semblera absent, et déclenchera une erreur applicative. Là aussi, la seule solution est d’utiliser un «hint».
  • Il est impossible de passer plusieurs requêtes dans un seul ordre SQL dans Pgpool-II, alors que c’est supporté par PostgreSQL.
  • Pgpool-II permet un cache de résultat de requête. Cette fonctionnalité est la plupart du temps une mauvaise idée : même sur une seule base, deux sessions exécutant la même requête simultanément ne verront pas forcément le même résultat, puisque ces sessions sont isolées dans des transactions différentes. Par ailleurs, la mise en place de ce genre de cache au niveau de la base de données impose un mécanisme d’invalidation du cache en cas de modification des tables sous-jacentes, extrêmement coûteux en performances.
  • Pgpool-II permet une bascule transparente entre le maître et l’esclave. Les requêtes en cours sont, en revanche, annulées. La fonctionnalité de watchdog introduite avec Pgpool-II 3.2 n’avait manifestement pas été testée (correction de bugs par Dalibo à l’époque). Il y a toujours des bugs ouverts sur le watchdog à ce jour.
  • Pgpool-II permet d’améliorer les performances d’une application se connectant à la base à chaque traitement. Cette fonctionnalité est bien mieux implémentée soit par un pooler applicatif (comme C3P0 en Java par exemple), ou par PGBouncer.
  • Pgpool-II introduit une latence supplémentaire entre le client et le serveur PostgreSQL : en effet, il analyse toutes les requêtes le traversant, en utilisant le même analyseur syntaxique que PostgreSQL. Ceci a donc un effet perceptible sur le temps d’exécution des requêtes. Cet effet a été mesuré chez un de nos clients, qui a constaté une dégradation des temps de réponse d’un facteur 2.5.
  • Pgpool-II introduit un Single Point Of Failure. Il doit donc être mis en haute disponibilité, ce qui complique bien sûr l’infrastructure.
  • La répartition de charge de Pgpool-II est très aléatoire : malgré la pondération présente dans la configuration, il est très difficile de respecter les poids indiqués : la principale contrainte est d’envoyer toutes les transactions réalisant des modifications vers le maître.
  • Pgpool-II consomme de nombreuses connexions aux bases, inutilement : sa méthode de pooling elle-même est très inefficace.
  • Le code de Pgpool-II est très fragile… un code capable de gérer toutes ces fonctionnalités simultanément est complexe à écrire, et ne l’a pas été fait de façon très rigoureuse sur ce projet, entraînant de nombreux effets de bord du code d’un mode lorsqu’on en utilise un autre.
  • La réplication «par requêtes» (mode replication de Pgpool-II) est une très mauvaise idée : pour pouvoir fonctionner, il est nécessaire de réécrire les requêtes à la volée (que se passe-t-il sinon quand on envoie INSERT INTO ma_table VALUES (now()) sur deux bases quasi-simultanément ?), et de sérialiser de nombreuses opérations pour que les différents ordres retournent le même résultat sur les différents nœuds.

Pour toutes ces raisons, Dalibo déconseille très fortement l’utilisation de Pgpool-II. Il est préférable de se tourner vers d’autres solutions, pour résoudre toutes ces problématiques :

  • Utilisation de deux pools distincts : un en lecture et écriture, synchrone, et un autre pour les lectures asynchrones. Initialement, toutes les requêtes sont exécutées par le premier pool. Les tests de performance, et les mesures en production permettent de cibler les quelques requêtes gourmandes, souvent des générations de rapports, des interrogations de catalogues d’articles, des constructions de nomenclature de produits… qui peuvent être redirigées vers les esclaves simplement en changeant le pool dans l’application.
  • Utilisation de PGBouncer si un pooler de connexion est nécessaire. PGBouncer est très supérieur à Pgpool-II pour la gestion du pooling de sessions.
  • Utilisation d’un boîtier (type F5), de IPVS (Linux), de HaProxy, pour la répartition de sessions sur plusieurs esclaves, ou n’importe quelle autre technique de load balancing mature.
  • Utilisation éventuelle d’un outil de clustering (Pacemaker sous Linux, associé à l’agent PAF) pour gérer la bascule vers un esclave si le maître venait à manquer. Souvent, un simple script de bascule est suffisant, si les contraintes de haute disponibilité ne sont pas très fortes : une bascule manuelle ne se produira qu’à partir du moment où l’administrateur en aura pris la décision, ce qui réduit le risque de bascule intempestive (et la perte de données qui peut l’accompagner).

Pgpool-II est presque systématiquement identifié comme point problématique sur les architectures auditées.