PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Un guide d'utilisation de pgBouncer pour PostgreSQL

Lors de la lecture du démarrage de PostgreSQL, vous voyez la ligne :"Le serveur PostgreSQL peut gérer plusieurs connexions simultanées à partir de clients. Pour ce faire, il démarre (« forks ») un nouveau processus pour chaque connexion. À partir de ce moment, le client et le nouveau processus serveur communiquent sans intervention du processus postgres d'origine. Ainsi, le processus du serveur maître est toujours en cours d'exécution, en attente de connexions client, tandis que les processus client et serveur associé vont et viennent.

Idée brillante. Et pourtant, cela signifie que chaque nouvelle connexion exécute un nouveau processus, réservant de la RAM et devenant peut-être trop lourde avec plusieurs sessions. Pour éviter les problèmes, postgres a un paramètre max_connections avec 100 connexions par défaut. Bien sûr, vous pouvez l'augmenter, mais une telle action nécessiterait un redémarrage (pg_settings.context est 'postmaster') :

t=# select name,setting,short_desc,context from pg_settings where name = 'max_connections';
-[ RECORD 1 ]--------------------------------------------------
name       | max_connections
setting    | 100
short_desc | Sets the maximum number of concurrent connections.
context    | postmaster
Quelques lectures passionnantes Utilisation de PgBouncer À quoi bon rebondir ? PgBouncer Changelog Posts contenant "pgbouncer" sur Stack Overflow Posts tagués "pgbouncer" sur 2ndQuadrant

Et même après avoir augmenté - à un moment donné, vous pourriez avoir besoin de plus de connexions (bien sûr de toute urgence, comme toujours sur la production en cours). Pourquoi l'augmenter est-il si inconfortable ? Parce que si c'était confortable, vous vous retrouveriez probablement avec une augmentation spontanée incontrôlée du nombre jusqu'à ce que le cluster commence à prendre du retard. Cela signifie que les anciennes connexions sont plus lentes - elles prennent donc plus de temps, vous avez donc besoin de plus en plus de nouvelles. Pour éviter une telle avalanche possible et ajouter une certaine flexibilité, nous avons superuser_reserved_connections - pour pouvoir se connecter et résoudre les problèmes avec SU lorsque max_connections est épuisé. Et nous voyons évidemment le besoin d'un pooler de connexion. Comme nous voulons que les nouveaux candidats à la connexion attendent dans une file d'attente au lieu d'échouer avec l'exception FATAL :désolé, trop de clients déjà et ne pas risquer le postmaster.

La mise en commun des connexions est proposée à un certain niveau par de nombreux « clients » populaires. Vous pouvez l'utiliser avec jdbc pendant un certain temps. Récemment, node-postgres a proposé son propre pool de nœuds-pg. Plus ou moins la mise en œuvre est simple (comme l'idée est) :pooler démarre les connexions vers la base de données et les conserve. Le client qui se connecte à la base de données n'obtient qu'une connexion existante "partagée" et après l'avoir fermée, la connexion revient au pool. Nous avons également des logiciels beaucoup plus sophistiqués, comme pgPool. Et pourtant, pgbouncer est un choix extrêmement populaire pour cette tâche. Pourquoi? Parce qu'il ne fait que la partie mise en commun, mais le fait bien. C'est gratuit. C'est assez simple à mettre en place. Et vous le rencontrez chez la plupart des plus grands fournisseurs de services recommandés ou utilisés, par exemple citusdata, aws, heroku et d'autres ressources hautement respectées.

Alors regardons de plus près ce qu'il peut et comment vous l'utilisez. Dans ma configuration, j'utilise par défaut pool_mode =transaction (section [pgbouncer]) qui est un choix très populaire. De cette façon, nous ne nous contentons pas de mettre en file d'attente les connexions dépassant max_connections, mais plutôt de réutiliser les sessions sans attendre la fermeture de la connexion précédente :

[databases]
mon = host=1.1.1.1 port=5432 dbname=mon
mons = host=1.1.1.1 port=5432 dbname=mon pool_mode = session pool_size=2 max_db_connections=2
monst = host=1.1.1.1 port=5432 dbname=mon pool_mode = statement
[pgbouncer]
listen_addr = 1.1.1.1
listen_port = 6432
unix_socket_dir = /tmp
auth_file = /pg/pgbouncer/bnc_users.txt
auth_type = hba
auth_hba_file = /pg/pgbouncer/bnc_hba.conf
admin_users = root vao
pool_mode = transaction
server_reset_query = RESET ALL; --DEALLOCATE ALL; /* custom */
ignore_startup_parameters = extra_float_digits
application_name_add_host = 1
max_client_conn = 10000
autodb_idle_timeout = 3600
default_pool_size = 100
max_db_connections = 100
max_user_connections = 100
#server_reset_query_always = 1 #uncomment if you want older global behaviour

Bref aperçu des paramètres les plus populaires et trucs et astuces :

  • server_reset_query est très pratique et important. En mode de regroupement de sessions, il "efface" les "artefacts" de la session précédente. Sinon, vous auriez des problèmes avec les mêmes noms pour les instructions préparées, les paramètres de session affectant les sessions suivantes, etc. La valeur par défaut est DISCARD ALL, qui "réinitialise" tous les états de session. Cependant, vous pouvez choisir des valeurs plus sophistiquées, par exemple, RESET ALL ; TOUT DÉSAFFECTER ; pour n'oublier que SET SESSION et les instructions préparées, en gardant les tables TEMP et les plans "partagés". Ou le contraire - vous voudrez peut-être faire des déclarations préparées "globales" à partir de n'importe quelle session. Une telle configuration est faisable, bien que risquée. Vous devez faire en sorte que pgbouncer réutilise la session pour tous (faisant ainsi une très petite taille de pool ou avalant les sessions), ce qui n'est pas complètement fiable. Quoi qu'il en soit - c'est une capacité utile. Surtout dans les configurations où vous souhaitez que les sessions client changent éventuellement (pas immédiatement) les paramètres de session regroupés configurés. Le point très important ici est le mode pool de sessions. Avant la version 1.6, ce paramètre affectait également les autres modes de pool, donc si vous vous y fiez, vous devez utiliser le nouveau paramètre server_reset_query_always =1. Probablement à un moment donné, les gens voudront que server_reset_query soit encore plus flexible et configurable par paire db/user ( et client_reset_query à la place). Mais au moment de la rédaction, mars 2018, ce n'est pas une option. L'idée de rendre ce paramètre valide par défaut pour le mode session uniquement était - si vous partagez la connexion au niveau de la transaction ou de l'instruction - vous ne pouvez pas du tout vous fier au paramètre de session.

  • Auth_type =hba. Avant la 1.7, le gros problème avec pgbouncer était l'absence d'authentification basée sur l'hôte - "pare-feu postgres". Bien sûr, vous l'aviez toujours pour la connexion au cluster postgres, mais pgbouncer était "ouvert" pour n'importe quelle source. Nous pouvons maintenant utiliser le même hba.conf pour limiter les connexions pour l'hôte/la base de données/l'utilisateur en fonction du réseau de connexion.

  • connect_query n'est pas exécuté sur chaque "connexion" client à pgbouncer, mais plutôt lorsque pgbouncer se connecte à une instance Postgres. Ainsi, vous ne pouvez pas l'utiliser pour définir ou remplacer les paramètres "par défaut". En mode session, les autres sessions ne s'affectent pas et lors de la déconnexion, la réinitialisation de la requête supprime tout - vous n'avez donc pas besoin de vous en soucier. En mode de regroupement de transactions, vous espérez l'utiliser pour remplacer les paramètres définis par erreur par d'autres sessions, mais cela ne fonctionnera pas, hélas. Par exemple. vous souhaitez partager une déclaration préparée entre les "sessions" en mode transaction, vous définissez donc quelque chose comme

    trns = dbname=mon pool_mode = transaction connect_query = 'do $$ begin raise warning $w$%$w$, $b$new connection$b$; end; $$; prepare s(int) as select $1;'

    et en effet - chaque nouveau client voit les instructions préparées (sauf si vous avez laissé server_reset_query_always activé, donc pgbouncer le supprime lors de la validation). Mais si un client exécute DISCARD s; dans sa session, il affecte tous les clients sur cette connexion et les nouveaux clients qui s'y connectent ne verront plus les instructions préparées. Mais si vous voulez avoir un réglage initial pour les connexions postgres provenant de pgbouncer, alors c'est ici.

  • application_name_add_host a été ajouté en 1.6, il a une limitation similaire. Il "met" l'adresse IP du client à application_name, de sorte que vous pouvez facilement obtenir votre mauvaise source de requête, mais est facilement remplacé par un simple set application_name TO 'wasn''t me' ; Vous pouvez toujours "réparer" cela en utilisant des vues - suivez ce post pour avoir une idée ou même utilisez ces courtes instructions. Fondamentalement, l'idée est que montrer aux clients ; affichera l'adresse IP des clients, vous pouvez donc l'interroger directement à partir de la base de données pgbouncer à chaque sélection de pg_stat_activity pour vérifier si elle est réinitialisée. Mais bien sûr, utiliser un cadre simple est beaucoup plus simple et plus confortable. Bien que cela ne garantisse pas le résultat...

  • pool_mode peut être spécifié à la fois par défaut, par base de données et par utilisateur, ce qui le rend très flexible. Les modes de mixage rendent pgbouncer extrêmement efficace pour le pooling. C'est une fonctionnalité puissante, mais il faut être prudent lors de son utilisation. Souvent, les utilisateurs l'utilisent sans comprendre les résultats pour des mélanges absolument atomiques de par transaction/par session/par utilisateur/par base de données/paramètres globaux fonctionnant différemment pour le même utilisateur ou la même base de données, en raison des différents modes de regroupement avec pgbouncer. C'est la boîte d'allumettes qu'on ne donne pas aux enfants sans surveillance. De nombreuses autres options sont également configurables par défaut, par base de données et par utilisateur.

  • S'il vous plaît ne le prenez pas au pied de la lettre, mais vous pouvez "comparer" différentes sections de ini avec SET et ALTER :SET LOCAL affecte les transactions et est bon à utiliser lorsque poll_mode=transaction , SET SESSION affecte les sessions et peut être utilisé en toute sécurité lorsque poll_mode=session , ALTER USER SET affecte les rôles et interfère avec la partie pgbouncer.ini de la section [users], ALTER DATABASE SET affecte les bases de données et interfère avec la partie pgbouncer.ini de la section [databases], ALTER SYSTEM SET ou l'édition de postgres.conf affecte globalement les valeurs par défaut et est comparable par son effet à la section par défaut de pgbouncer.ini.

  • Encore une fois, utilisez le mode piscine de manière responsable. Les instructions préparées ou les paramètres à l'échelle de la session seront un gâchis en mode de regroupement des transactions. Identique à la transaction SQL qui n'a aucun sens en mode de regroupement d'instructions. Choisissez un mode de regroupement approprié pour les connexions appropriées. Une bonne pratique consiste à créer des rôles avec l'idée que :

    • certains n'exécutent que des sélections rapides, et peuvent donc partager une session sans transactions pour une centaine de petites sélections simultanées sans importance.
    • Certains membres de rôle sont sûrs pour la simultanéité au niveau de la session et utilisent TOUJOURS les transactions. Ainsi, ils peuvent partager en toute sécurité plusieurs sessions pour des centaines de transactions simultanées.
    • Certains rôles sont tout simplement trop désordonnés ou compliqués pour partager leur session avec d'autres. Vous utilisez donc pour eux le mode de regroupement de sessions pour éviter les erreurs de connexion lorsque tous les "slots" sont déjà pris.
  • Ne l'utilisez pas à la place de HAProxy ou d'un autre équilibreur de charge. Malgré le fait que pgbouncer dispose de plusieurs fonctionnalités configurables traitant de ce qu'adresse un équilibreur de charge, comme dns_max_ttl et que vous pouvez configurer une configuration DNS pour cela, la plupart des environnements de production utilisent HAProxy ou un autre équilibreur de charge pour HA. En effet, HAProxy est vraiment bon pour équilibrer la charge sur les serveurs en direct de manière circulaire, mieux que pgbouncer. Bien que pgbouncer soit meilleur pour le regroupement de connexions postgres, il serait peut-être préférable d'utiliser un petit démon qui exécute parfaitement une tâche, au lieu d'un plus gros qui effectue deux tâches, mais en pire.

  • Les changements de configuration peuvent être délicats. Certaines modifications apportées à pgbouncer.ini nécessitent un redémarrage (listen_port et autres), tandis que d'autres telles que admin_users nécessitent un rechargement ou SIGHUP. Les modifications apportées à auth_hba_file nécessitent un rechargement, contrairement aux modifications apportées à auth_file.

L'aperçu extrêmement court des paramètres ci-dessus est limité par le format. Je vous invite à consulter la liste complète. Pgbouncer est le genre de logiciel avec très peu de "paramètres ennuyeux" - ils ont tous un potentiel énorme et sont d'un intérêt incroyable.

Téléchargez le livre blanc aujourd'hui PostgreSQL Management &Automation with ClusterControlDécouvrez ce que vous devez savoir pour déployer, surveiller, gérer et faire évoluer PostgreSQLTélécharger le livre blanc

Et enfin, passer d'une courte critique enthousiaste à quelque chose où vous pourriez être moins heureux - l'installation. Le processus est clairement décrit dans cette section de la documentation. La seule option décrite est la construction à partir de sources git. Mais tout le monde sait qu'il y a des forfaits ! Essayer les deux plus populaires :

sudo yum install pgbouncer
sudo apt-get install pgbouncer

peut marcher. Mais parfois, vous devez faire une étape supplémentaire. Par exemple, lorsqu'aucun package pgbouncer n'est disponible, essayez ceci.

Ou encore :

sudo yum install pgbouncer
Loaded plugins: priorities, update-motd, upgrade-helper
amzn-main                                                                                                                    | 2.1 kB  00:00:00
amzn-updates                                                                                                                 | 2.5 kB  00:00:00
docker-ce-edge                                                                                                               | 2.9 kB  00:00:00
docker-ce-stable                                                                                                             | 2.9 kB  00:00:00
docker-ce-test                                                                                                               | 2.9 kB  00:00:00
pgdg10                                                                                                                       | 4.1 kB  00:00:00
pgdg95                                                                                                                       | 4.1 kB  00:00:00
pgdg96                                                                                                                       | 4.1 kB  00:00:00
pglogical                                                                                                                    | 3.0 kB  00:00:00
sensu                                                                                                                        | 2.5 kB  00:00:00
(1/3): pgdg96/x86_64/primary_db                                                                                              | 183 kB  00:00:00
(2/3): pgdg10/primary_db                                                                                                     | 151 kB  00:00:00
(3/3): pgdg95/x86_64/primary_db                                                                                              | 204 kB  00:00:00
50 packages excluded due to repository priority protections
Resolving Dependencies
--> Running transaction check
---> Package pgbouncer.x86_64 0:1.8.1-1.rhel6 will be installed
--> Processing Dependency: libevent2 >= 2.0 for package: pgbouncer-1.8.1-1.rhel6.x86_64
--> Processing Dependency: c-ares for package: pgbouncer-1.8.1-1.rhel6.x86_64
--> Processing Dependency: libcares.so.2()(64bit) for package: pgbouncer-1.8.1-1.rhel6.x86_64
--> Running transaction check
---> Package c-ares.x86_64 0:1.13.0-1.5.amzn1 will be installed
---> Package pgbouncer.x86_64 0:1.8.1-1.rhel6 will be installed
--> Processing Dependency: libevent2 >= 2.0 for package: pgbouncer-1.8.1-1.rhel6.x86_64
--> Finished Dependency Resolution
Error: Package: pgbouncer-1.8.1-1.rhel6.x86_64 (pgdg10)
           Requires: libevent2 >= 2.0
 You could try using --skip-broken to work around the problem
 You could try running: rpm -Va --nofiles --nodigest

Bien sûr, ajouter pgdg à /etc/yum.repos.d/ n'aidera plus. Ni --skip-broken ni rpm -Va --nofiles --nodigest. Un simple

sudo yum install libevent2
Loaded plugins: priorities, update-motd, upgrade-helper
50 packages excluded due to repository priority protections
No package libevent2 available.
Error: Nothing to do

serait trop facile. Vous devez donc construire vous-même libevent2, ce qui vous ramène à la position où vous devez compiler les choses vous-même. Soit c'est pgbouncer ou l'une de ses dépendances.

Encore une fois - creuser trop profondément avec les particularités de l'installation est hors de portée. Vous devez savoir que vous avez de grandes chances de l'installer en tant que package.

Enfin, des questions telles que "pourquoi postgres n'offre pas de pool de sessions natif" reviennent sans cesse. Il y a même des suggestions et des réflexions très fraîches à ce sujet. Mais jusqu'à présent, l'approche la plus populaire ici utilise pgbouncer.