L'équilibrage de charge augmente les performances du système, en particulier du point de vue de l'application, permettant à plusieurs ordinateurs de servir les mêmes données. Cela fonctionne de telle sorte que la charge est répartie entre les requêtes client vers les nœuds réplicas en dehors de son nœud principal ou maître, tout en acheminant les modifications de la base de données uniquement vers le nœud maître seul. Toutes les modifications apportées au nœud maître sont ensuite propagées à chaque réplica à l'aide de PostgreSQL Streaming Replication.
Comment les équilibreurs de charge peuvent-ils affecter PostgreSQL ?
L'utilisation de l'équilibrage de charge doit diriger les applications clientes pour se connecter au serveur d'équilibrage de charge et distribuer les connexions initiées aux nœuds PostgreSQL disponibles en fonction du type de requêtes. Cela aide à réduire la charge exceptionnelle sur un serveur PostgreSQL particulier et favorise l'équilibre parallèle de la charge entre les nœuds disponibles au sein du cluster.
En utilisant PostgreSQL, il existe déjà une poignée de solutions existantes pour que cela fonctionne. Ces solutions peuvent fonctionner de manière transparente ou l'équilibrage de charge peut fonctionner avec la topologie actuelle - avec des nœuds principaux et de secours - mais l'équilibrage de charge est implémenté dans la couche d'application elle-même. L'équilibrage de charge est confronté à des problèmes de synchronisation, ce qui est la difficulté fondamentale pour les serveurs travaillant ensemble. Parce qu'il n'y a pas de solution unique qui élimine l'impact du problème de synchronisation pour tous les cas d'utilisation, il existe plusieurs solutions. Chaque solution résout ce problème d'une manière différente et minimise son impact pour une charge de travail spécifique.
Dans ce blog, nous examinerons ces équilibreurs de charge en les comparant et en quoi ils sont bénéfiques pour votre charge de travail PostgreSQL.
Équilibrage de charge HAProxy pour PostgreSQL
HAProxy est un moteur non bloquant piloté par les événements combinant un proxy avec une couche d'E/S très rapide et un planificateur multithread basé sur la priorité. Comme il est conçu avec un objectif de transfert de données à l'esprit, son architecture est conçue pour fonctionner dans un processus léger optimisé pour déplacer les données aussi rapidement que possible avec le moins d'opérations possibles. Il se concentre sur l'optimisation de l'efficacité du cache du processeur en conservant les connexions au même processeur aussi longtemps que possible. En tant que tel, il implémente un modèle en couches offrant des mécanismes de contournement à chaque niveau garantissant que les données n'atteignent pas des niveaux supérieurs, sauf si nécessaire. La plupart des traitements sont effectués dans le noyau. HAProxy fait de son mieux pour aider le noyau à faire le travail le plus rapidement possible en donnant quelques conseils ou en évitant certaines opérations lorsqu'il devine qu'elles pourraient être regroupées plus tard. En conséquence, les chiffres typiques montrent 15 % du temps de traitement passé dans HAProxy contre 85 % dans le noyau en mode de fermeture TCP ou HTTP, et environ 30 % pour HAProxy contre 70 % pour le noyau en mode HTTP keep-alive.
HAProxy possède également des fonctionnalités supplémentaires d'équilibrage de charge. Par exemple, la fonctionnalité de proxy TCP nous permet de l'utiliser pour les connexions à la base de données, en particulier pour PostgreSQL, en utilisant son support de service de vérification intégré. Même s'il existe un support de service de base de données, cela ne suffit pas à la vérification de l'état souhaitée, en particulier pour un type de cluster de réplication. L'approche standard lors du déploiement en production consiste à utiliser la vérification TCP, puis à dépendre de xinetd avec HAProxy.
Avantages de l'utilisation de HAProxy pour PostgreSQL
La meilleure chose avec HAProxy est sa légèreté, sa facilité de configuration et d'utilisation, et il fait le travail comme prévu. L'utilisation de HAProxy au-dessus d'un cluster PostgreSQL a été implémentée et déployée à plusieurs reprises depuis de grandes organisations vers diverses PME/PME pour leur utilisation en production. Il a fait ses preuves depuis longtemps pour la production et la capacité de charge de travail élevée, non seulement pour les bases de données, mais même avec d'autres services réseau tels que les applications Web ou pour l'équilibrage de la charge géographique (distribution du trafic sur plusieurs centres de données). Ayant HAProxy au-dessus de PostgreSQL, il permet aux utilisateurs de limiter ou de limiter les réponses pour paralléliser et distribuer correctement la charge à tous les nœuds disponibles dans le cluster. Le mécanisme intégré avec HAProxy permet également à l'utilisateur de configurer la haute disponibilité de manière transparente et plus facile à mettre à l'échelle si une charge est nécessaire et d'éviter le point de défaillance unique (SPOF).
Inconvénients de l'utilisation de HAProxy pour PostgreSQL
HAProxy ne fournit pas de filtrage de requête ni d'analyse de requête pour identifier le type d'instructions demandées. Il n'a pas la capacité d'effectuer une séparation lecture/écriture sur un seul port. La configuration d'un équilibreur de charge au-dessus de HAProxy nécessite que vous deviez au moins configurer différents ports pour vos écritures et différents pour vos lectures. Cela nécessite des modifications de l'application pour répondre à vos besoins.
HAProxy prend également en charge une fonctionnalité très simple avec PostgreSQL pour la vérification de l'état, mais cela ne détermine que si le nœud est opérationnel ou non, comme s'il faisait juste un ping sur le nœud et attend une réponse de rebond. Il n'identifie pas le rôle d'un nœud qu'il essaie de transmettre les connexions demandées du client au nœud souhaité. Par conséquent, il ne comprend pas ou pas de fonctionnalité dans HAProxy pour comprendre la topologie de réplication. Bien qu'un utilisateur puisse créer des écouteurs distincts basés sur différents ports, il ajoute néanmoins des modifications au sein de l'application pour répondre aux besoins d'équilibrage de charge. Cela signifie que l'utilisation d'un script externe avec xinetd peut être la solution de contournement pour remplir les exigences. Cependant, il n'est pas intégré à HAProxy et peut être sujet à des erreurs humaines.
Si un nœud ou un groupe de nœuds doit être placé en mode maintenance, vous devrez également appliquer des modifications à votre HAProxy, sinon cela peut être catastrophique.
Pgpool-II pour l'équilibrage de charge de votre PostgreSQL
Pgpool-II est un logiciel open-source et est adopté par l'énorme communauté PostgreSQL pour implémenter l'équilibrage de charge et l'utiliser pour agir comme leur middleware de l'application jusqu'à la couche proxy, puis distribue la charge après avoir entièrement analysé le type de requête par requête ou connexion à la base de données. Pgpool-II existe depuis si longtemps depuis 2003, qui s'appelait à l'origine Pgpool jusqu'à ce qu'il devienne Pgpool-II en 2006, qui témoigne d'un outil proxy très stable non seulement pour l'équilibrage de charge, mais également pour des tonnes de fonctionnalités intéressantes. .
Pgpool-II est connu comme le couteau suisse de PostgreSQL et est un logiciel proxy qui se situe entre les serveurs PostgreSQL et un client de base de données PostgreSQL. L'idée de base de PgPool-II est qu'il repose sur le client, puis les requêtes de lecture doivent être livrées aux nœuds de secours, tandis que l'écriture ou les modifications vont directement au primaire. Il s'agit d'une solution d'équilibrage de charge très intelligente qui non seulement équilibre la charge, mais prend également en charge la haute disponibilité et fournit un pool de connexions. Le mécanisme intelligent permet d'équilibrer la charge entre les maîtres et les esclaves. Ainsi, les écritures sont chargées sur le maître, tandis que le traitement des lectures est dirigé vers les serveurs en lecture seule disponibles, qui sont vos nœuds de secours supposés. Pgpool-II fournit également une réplication logique. Bien que son utilisation et son importance aient diminué à mesure que les options de réplication intégrées se sont améliorées côté serveur PostgreSQL, cela reste une option précieuse pour les anciennes versions de PostgreSQL. En plus de tout cela, il fournit également un regroupement de connexions.
Pgpool-II a une architecture plus complexe que PgBouncer afin de prendre en charge toutes les fonctionnalités qu'il propose. Étant donné que les deux prennent en charge le regroupement de connexions, ce dernier n'a pas de fonctionnalités d'équilibrage de charge.
Pgpool-II peut gérer plusieurs serveurs PostgreSQL. L'utilisation de la fonction de réplication permet de créer une sauvegarde en temps réel sur 2 disques physiques ou plus, afin que le service puisse continuer sans arrêter les serveurs en cas de panne de disque. Étant donné que Pgpool-II est également capable de regrouper des connexions, il peut fournir une limitation des connexions excédentaires. Il y a une limite au nombre maximum de connexions simultanées avec PostgreSQL, et les connexions sont rejetées après ce nombre de connexions. Toutefois, la définition du nombre maximal de connexions augmente la consommation de ressources et affecte les performances du système. pgpool-II a également une limite sur le nombre maximum de connexions, mais les connexions supplémentaires seront mises en file d'attente au lieu de renvoyer une erreur immédiatement.
En équilibrage de charge, si une base de données est répliquée, l'exécution d'une requête SELECT sur n'importe quel serveur renverra le même résultat. pgpool-II tire parti de la fonctionnalité de réplication pour réduire la charge sur chaque serveur PostgreSQL en distribuant les requêtes SELECT entre plusieurs serveurs, améliorant ainsi le débit global du système. Au mieux, les performances s'améliorent proportionnellement au nombre de serveurs PostgreSQL. L'équilibrage de charge fonctionne mieux dans une situation où de nombreux utilisateurs exécutent plusieurs requêtes en même temps.
À l'aide de la fonction de requête parallèle, les données peuvent être réparties entre plusieurs serveurs, de sorte qu'une requête peut être exécutée simultanément sur tous les serveurs afin de réduire le temps d'exécution global. La requête parallèle fonctionne mieux lors de la recherche de données à grande échelle.
Avantages de l'utilisation de Pgpool pour PostgreSQL
C'est un type de logiciel riche en fonctionnalités, pas seulement pour l'équilibrage de charge. Les principales fonctionnalités et la prise en charge de cet outil sont hautement à la demande, ce qui fournit un regroupement de connexions, une alternative à PgBouncer, une réplication native, une récupération en ligne, une mise en cache des requêtes en mémoire, un basculement automatique et une haute disponibilité avec son sous-processus utilisant un chien de garde. Cet outil est si ancien et est continuellement pris en charge massivement par la communauté PostgreSQL, il n'est donc pas difficile de trouver de l'aide pour résoudre les problèmes. La documentation est votre amie ici lorsque vous cherchez des questions, mais chercher de l'aide dans la communauté n'est pas difficile, et le fait que cet outil est une source ouverte vous pouvez donc l'utiliser librement tant que vous respectez la licence BSD.
Pgpool-II dispose également d'un analyseur SQL. Cela signifie qu'il est capable d'analyser avec précision les SQL et de réécrire la requête. Cela permet à Pgpool-II d'augmenter le parallélisme en fonction de la demande de requête.
Inconvénients de l'utilisation de Pgpool pour PostgreSQL
Pgpool-II n'offre pas STONITH (tirer sur l'autre nœud dans la tête) qui fournit un mécanisme de clôture de nœud. Si le serveur PostgreSQL tombe en panne, il maintient la disponibilité du service. Pgpool-II peut également être le point de défaillance unique (SPOF). Une fois que le nœud tombe en panne, la connectivité et la disponibilité de votre base de données s'arrêtent à partir de ce point. Bien que cela puisse être résolu en ayant une redondance avec Pgpool-II et en devant utiliser un chien de garde pour coordonner plusieurs nœuds Pgpool-II, cela ajoute du travail supplémentaire.
Pour le regroupement de connexions, malheureusement, pour ceux qui se concentrent uniquement sur le regroupement de connexions, ce que Pgpool-II ne fait pas très bien, c'est le regroupement de connexions, en particulier pour un petit nombre de clients. Étant donné que chaque processus enfant a son propre pool et qu'il n'y a aucun moyen de contrôler quel client se connecte à quel processus enfant, trop de chance est laissée à la chance lorsqu'il s'agit de réutiliser les connexions.
Utilisation du pilote JDBC pour l'équilibrage de charge de votre PostgreSQL
Java Database Connectivity (JDBC) est une interface de programmation d'application (API) pour le langage de programmation Java, qui définit comment un client peut accéder à une base de données. Il fait partie de la plate-forme Java Standard Edition et fournit des méthodes pour interroger et mettre à jour les données d'une base de données, et est orienté vers les bases de données relationnelles.
Le pilote PostgreSQL JDBC (PgJDBC en abrégé) permet aux programmes Java de se connecter à une base de données PostgreSQL à l'aide d'un code Java standard indépendant de la base de données. Est un pilote JDBC open source écrit en Pure Java (Type 4) et communique dans le protocole réseau natif PostgreSQL. Pour cette raison, le pilote est indépendant de la plate-forme; une fois compilé, le pilote peut être utilisé sur n'importe quel système.
Ce n'est pas comparable aux solutions d'équilibrage de charge que nous avons signalées précédemment. Par conséquent, cet outil est votre API d'interface de programmation d'application qui vous permet de vous connecter à partir de votre application pour n'importe quel type de langage de programmation écrit qui prend en charge JDBC ou qui a au moins un adaptateur pour se connecter à JDBC. En revanche, c'est plus favorable avec les applications Java.
L'équilibrage de charge avec JDBC est assez naïf mais peut faire le travail. Fourni avec les paramètres de connexion qui peuvent déclencher le mécanisme d'équilibrage de charge que cet outil a à offrir,
- targetServerType - permet d'ouvrir des connexions uniquement aux serveurs avec l'état/le rôle requis conformément au facteur de définition des serveurs PostgreSQL. Les valeurs autorisées sont any, primary, master (obsolète), slave (obsolète), Secondary, preferSlave et preferSecondary. L'état ou le rôle est déterminé en observant si le serveur autorise ou non les écritures.
- hostRecheckSeconds - contrôle la durée en secondes pendant laquelle les connaissances sur l'état d'un hôte sont mises en cache dans le cache global de la JVM. La valeur par défaut est de 10 secondes.
- loadBalanceHosts - vous permet de configurer si le premier hôte est toujours essayé (lorsqu'il est défini sur false) ou si les connexions sont choisies au hasard (lorsqu'il est défini sur true)
Utilisez donc loadBalanceHosts qui accepte une valeur booléenne. loadBalanceHosts est désactivé en mode par défaut et les hôtes sont connectés dans l'ordre indiqué. Si activé, les hôtes sont choisis au hasard parmi l'ensemble des candidats appropriés. La syntaxe de base lors de la connexion à la base de données à l'aide de jdbc est la suivante,
- jdbc:postgresql:database
- jdbc:postgresql:/
- jdbc:postgresql://host/database
- jdbc:postgresql://host/
- jdbc:postgresql://host:port/database
- jdbc:postgresql://host:port/
Étant donné que loadBalanceHosts et la connexion reçoivent plusieurs hôtes configurés comme ci-dessous,
jdbc:postgresql://host1:port1,host2:port2,host3:port3/database
Cela permet à JDBC de choisir au hasard parmi l'ensemble de candidats appropriés.
Avantages de l'utilisation de PgJDBC pour PostgreSQL
Pas besoin d'exiger un middleware ou un proxy comme équilibreurs de charge. Ce processus augmente davantage les performances de l'interface de l'application car il n'y a pas de couche supplémentaire pour chaque demande à passer. Si vous avez des applications prêtes et écrites pour prendre en charge l'interfaçage avec JDBC, cela peut être avantageux et si vous n'avez pas besoin de plus de middleware, surtout si votre budget est serré et que vous souhaitez limiter uniquement les processus dédiés à son seul objectif et fonction. Contrairement aux applications à fort trafic et à forte demande, cela peut nécessiter des serveurs proxy agissant comme vos équilibreurs de charge et peut exiger des ressources supplémentaires pour gérer correctement les demandes élevées de connexions, ce qui nécessite également une demande de traitement du processeur et de la mémoire.
Inconvénients de l'utilisation de PgJDBC pour PostgreSQL
Vous devez configurer votre code pour chaque connexion à demander. Il s'agit d'une interface de programmation d'application, ce qui signifie qu'il y a du travail derrière, surtout si votre application est très exigeante sur chaque demande à envoyer aux serveurs appropriés. Il n'y a pas de haute disponibilité, d'évolutivité automatique et un point de défaillance unique.
Que diriez-vous des wrappers ou des outils implémentés avec libpq pour l'équilibrage de charge de votre PostgreSQL ?
libpq est l'interface du programmeur d'application C vers PostgreSQL. libpq est un ensemble de fonctions de bibliothèque qui permettent aux programmes clients de transmettre des requêtes au serveur principal PostgreSQL et de recevoir les résultats de ces requêtes.
libpq est également le moteur sous-jacent de plusieurs autres interfaces d'application PostgreSQL, y compris celles écrites pour C++, PHP, Perl, Python, Tcl, Swift et ECPG. Ainsi, certains aspects du comportement de libpq seront importants pour vous si vous utilisez l'un de ces packages.
libpq n'automatise pas l'équilibrage de charge et ne doit pas être considéré comme un outil pour les solutions d'équilibrage de charge. Pourtant, il est capable de se connecter aux prochains serveurs disponibles si les serveurs précédents répertoriés pour la connexion échouent. Par exemple, si vous avez deux nœuds de redondance disponibles, si le premier nœud est trop occupé et ne répond pas à la valeur de délai d'attente correspondante, il se connecte au nœud disponible suivant dans la connexion donnée. Cela dépend du type d'attributs de session que vous avez spécifié. Cela repose sur le paramètre target_session_attrs.
Le paramètre target_session_attrs accepte les valeurs en lecture-écriture, et toute valeur par défaut si elle n'est pas spécifiée. Ce que fait le paramètre target_session_attrs est que, s'il est défini sur lecture-écriture, seule une connexion dans laquelle les transactions en lecture-écriture sont acceptées lors de la connexion. La requête SHOW transaction_read_only sera envoyée lors de toute connexion réussie. Si le résultat est activé, la connexion sera fermée, ce qui signifie que le nœud est identifié comme une réplique ou ne traite pas les écritures. Si plusieurs hôtes ont été spécifiés dans la chaîne de connexion, tous les serveurs restants seront essayés comme si la tentative de connexion avait échoué. La valeur par défaut de ce paramètre, any, signifie que toutes les connexions sont acceptables. Bien que s'appuyer sur target_session_attrs ne soit pas suffisant pour l'équilibrage de charge, vous pourrez peut-être simuler un mode round-robin. Voir mon exemple de code C ci-dessous en utilisant libpq,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <libpq-fe.h>
const char* _getRoundRobinConn() {
char* h[2];
h[0] = "dbname=node40 host=192.168.30.40,192.168.30.50";
h[1] = "dbname=node50 host=192.168.30.50,192.168.30.40";
time_t t;
//srand((unsigned)time(&t));
sleep(1.85);
srand((unsigned)time(NULL));
return h[rand() % 2];
}
void
_connect()
{
PGconn *conn;
PGresult *res;
char strConn[120];
snprintf(strConn, 1000, "user=dbapgadmin password=dbapgadmin %s target_session_attrs=any", _getRoundRobinConn());
//printf("\nstrConn value is: %s\n", strConn);
conn = PQconnectdb(strConn);
res = PQexec(conn, "SELECT current_database(), inet_client_addr();");
if ( PQresultStatus(res)==PGRES_TUPLES_OK )
{
printf("current_database = %s on %s\n", PQgetvalue(res, 0, 0),
PQhost(conn));
} else {
printf("\nFailed... Message Code is: %d\n", PQresultStatus(res));
}
PQclear(res);
PQfinish(conn);
}
int main(void)
{
int i;
for (i=0 ; i<5 ; i++)
_connect();
return 0;
}
Le résultat révèle,
[email protected]:/home/vagrant# gcc -I/usr/include/postgresql -L/usr/lib/postgresql/12/lib libpq_conn.c -lpq -o libpq_conn; ./libpq_conn
current_database = node40 on 192.168.30.40
current_database = node40 on 192.168.30.40
current_database = node50 on 192.168.30.50
current_database = node40 on 192.168.30.40
current_database = node50 on 192.168.30.50
Notez que, si le nœud .40 (le nœud principal) tombe en panne, il dirigera toujours la connexion vers le .50 tant que votre valeur target_session_attrs est quelconque.
Dans ce cas, vous pouvez simplement créer le vôtre librement à l'aide de libpq. Bien que le processus consistant à s'appuyer sur libpq et/ou ses wrappers soit tout simplement trop brut pour dire que cela peut fournir le mécanisme d'équilibrage de charge souhaité avec une distribution uniforme sur les nœuds que vous avez. Certes, cette approche et ce codage peuvent être améliorés, mais l'idée est que c'est gratuit et open source, et vous pouvez coder sans vous fier aux middlewares et concevoir librement le fonctionnement de votre équilibrage de charge.
Les avantages de l'utilisation de libpq pour PostgresQL
La bibliothèque libpq est l'interface d'application du programmeur construite dans le langage de programmation C. Pourtant, la bibliothèque a été implémentée dans différents langages en tant que wrappers afin que les programmeurs puissent communiquer avec la base de données PostgreSQL en utilisant leurs langages préférés. Vous pouvez créer directement votre propre application en utilisant vos langages préférés, puis lister les serveurs auxquels vous souhaitez que les requêtes soient envoyées, mais uniquement les unes après les autres, en cas d'échec ou d'expiration du délai, envoyez votre charge aux nœuds disponibles que vous souhaitez répartir. la charge. Il est disponible dans des langages tels que Python, Perl, PHP, Ruby, Tcl ou Rust.
Inconvénients de l'utilisation de libpq pour PostgresQL
La mise en œuvre du parallélisme de charge n'est pas parfaite et vous devez écrire votre propre mécanisme d'équilibrage de charge par code. Il n'y a pas de configuration que vous pouvez utiliser ou personnaliser puisqu'il s'agit tout seul d'une interface de programmation vers la base de données PostgreSQL à l'aide du paramètre target_session_attrs. Cela signifie que lors de la composition d'une connexion à une base de données, vous devez disposer d'une série de connexions de lecture vers vos nœuds de réplique/de secours, puis écrire des requêtes qui vont au rédacteur ou au nœud principal de votre code, que ce soit dans votre application ou que vous deviez créer votre propre API pour gérer la solution d'équilibrage de charge.
L'utilisation de cette approche n'a certainement pas besoin ou ne repose pas sur un middleware du point de vue de l'application frontale à la base de données en tant que backend. Bien sûr, c'est léger, mais lors de l'envoi de la liste des serveurs lors de la connexion, cela ne signifie pas que la charge est comprise et envoyée uniformément, sauf si vous devez ajouter votre code pour cette approche. Cela ne fait que compliquer la tâche, mais il existe déjà des solutions, alors pourquoi réinventer la roue ?
Conclusion
La mise en œuvre de vos équilibreurs de charge avec PostgreSQL peut être exigeante, mais dépend du type d'application et du coût auxquels vous avez affaire. Parfois, pour une demande de charge élevée, cela nécessite le besoin d'un middleware agissant comme un proxy afin de répartir correctement la charge et de superviser également l'état ou la santé de son nœud. D'autre part, il peut exiger des ressources de serveur, soit il doit être exécuté sur un serveur dédié, soit il nécessite un processeur et une mémoire supplémentaires afin de satisfaire les besoins, ce qui augmente les coûts. Par conséquent, il existe également un moyen simple mais qui prend du temps mais qui offre la répartition de la charge sur les serveurs disponibles que vous avez déjà. Cependant, cela nécessite des compétences en programmation et une compréhension des fonctionnalités de l'API.