PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Eine Anleitung zur Verwendung von pgBouncer für PostgreSQL

Wenn Sie die ersten Schritte mit PostgreSQL lesen, sehen Sie die Zeile:„Der PostgreSQL-Server kann mehrere gleichzeitige Verbindungen von Clients verarbeiten. Um dies zu erreichen, wird für jede Verbindung ein neuer Prozess gestartet („forkt“). Ab diesem Zeitpunkt kommunizieren der Client und der neue Serverprozess ohne Eingriff des ursprünglichen Postgres-Prozesses. Daher läuft der Master-Server-Prozess immer und wartet auf Client-Verbindungen, während Client- und zugehörige Server-Prozesse kommen und gehen.

Brilliante Idee. Und doch bedeutet dies, dass jede neue Verbindung einen neuen Prozess startet, RAM reserviert und bei mehreren Sitzungen möglicherweise zu schwer wird. Um Probleme zu vermeiden, hat Postgres die Einstellung max_connections mit standardmäßig 100 Verbindungen. Natürlich können Sie es erhöhen, aber eine solche Aktion würde einen Neustart erfordern (pg_settings.context ist „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
Einige spannende Lektüre PgBouncer-Nutzung Was ist der Sinn des Bouncens? PgBouncer-Änderungsprotokoll Beiträge mit „pgbouncer“ auf Stack Overflow Beiträge mit dem Tag „pgbouncer“ auf 2ndQuadrant

Und auch nach dem Aufstocken - irgendwann braucht man vielleicht mehr Anschlüsse (natürlich dringend wie immer am laufenden prod). Warum es so unbequem ist, es zu erhöhen? Denn wenn es bequem wäre, würden Sie wahrscheinlich mit einem unkontrollierten spontanen Erhöhen der Zahl enden, bis der Cluster anfängt zu verzögern. Das heißt, alte Verbindungen sind langsamer - sie brauchen also mehr Zeit, sodass Sie immer mehr neue benötigen. Um eine solche mögliche Lawine zu vermeiden und etwas Flexibilität hinzuzufügen, haben wir superuser_reserved_connections - um in der Lage zu sein, eine Verbindung herzustellen und Probleme mit SU zu beheben, wenn max_connections erschöpft ist. Und wir sehen offensichtlich die Notwendigkeit eines Verbindungspoolers. Da wir möchten, dass neue Verbindungskandidaten in einer Warteschlange warten, anstatt mit Ausnahme FATAL zu scheitern:Entschuldigung, zu viele Clients bereits und kein Risiko für den Postmaster.

Connection Pooling wird auf einer gewissen Ebene von vielen beliebten „Clients“ angeboten. Sie könnten es eine ganze Weile mit jdbc verwenden. Vor kurzem bot node-postgres einen eigenen node-pg-pool an. Die Implementierung ist mehr oder weniger einfach (wie die Idee):pooler startet die Verbindungen zur Datenbank und hält sie aufrecht. Der Client, der sich mit db verbindet, erhält nur eine „geteilte“ bestehende Verbindung und nach dem Schließen geht die Verbindung zurück zum Pool. Wir haben auch viel ausgefeiltere Software wie pgPool. Und doch ist pgbouncer eine äußerst beliebte Wahl für diese Aufgabe. Wieso den? Weil es nur den Pooling-Teil macht, aber es richtig macht. Es ist kostenlos. Es ist ziemlich einfach einzurichten. Und Sie finden es bei den meisten größten Dienstanbietern wie empfohlen oder verwendet, zB citusdata, aws, heroku und andere hoch angesehene Ressourcen.

Schauen wir uns also genauer an, was es kann und wie Sie es verwenden. In meinem Setup verwende ich standardmäßig pool_mode =transaction (Abschnitt [pgbouncer]), was eine sehr beliebte Wahl ist. Auf diese Weise stellen wir nicht nur die Verbindungen in die Warteschlange, die max_connections überschreiten, sondern verwenden Sitzungen wieder, ohne auf das Schließen der vorherigen Verbindung zu warten:

[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

Kurzer Überblick über die beliebtesten Einstellungen und Tipps und Tricks:

  • server_reset_query ist sehr praktisch und wichtig. Im Session-Pooling-Modus „löscht“ es „Artefakte“ der vorherigen Session. Andernfalls hätten Sie Probleme mit gleichen Namen für vorbereitete Anweisungen, Sitzungseinstellungen, die sich auf nächste Sitzungen auswirken, und so weiter. Der Standardwert ist DISCARD ALL, wodurch alle Sitzungszustände „zurückgesetzt“ werden. Sie können jedoch anspruchsvollere Werte auswählen, z. B. ALLE ZURÜCKSETZEN; ALLE ZUORDNUNG AUFHEBEN; nur SET SESSION und vorbereitete Anweisungen zu vergessen, TEMP-Tabellen und Pläne „gemeinsam“ zu halten. Oder das Gegenteil – vielleicht möchten Sie vorbereitete Erklärungen „global“ aus jeder Sitzung machen. Eine solche Konfiguration ist machbar, wenn auch riskant. Sie müssen pgbouncer dazu bringen, die Sitzung für alle wiederzuverwenden (wodurch entweder die Poolgröße sehr klein wird oder die Sitzungen zu einer Lawine werden), was nicht vollständig zuverlässig ist. Wie auch immer - es ist eine nützliche Fähigkeit. Insbesondere in Setups, in denen Sie möchten, dass Clientsitzungen schließlich (nicht sofort) in konfigurierte gepoolte Sitzungseinstellungen geändert werden. Sehr wichtiger Punkt hier ist der Session-Pool-Modus. Vor 1.6 wirkte sich diese Einstellung auch auf andere Pool-Modi aus. Wenn Sie sich also darauf verlassen haben, müssen Sie die neue Einstellung server_reset_query_always =1 verwenden. Wahrscheinlich werden die Leute irgendwann wollen, dass server_reset_query noch flexibler und pro Datenbank/Benutzer-Paar konfigurierbar ist ( und stattdessen client_reset_query). Aber zum jetzigen Zeitpunkt, März 2018, ist dies keine Option. Die Idee dahinter, diese Einstellung standardmäßig nur für den Sitzungsmodus gültig zu machen, war - wenn Sie die Verbindung auf Transaktions- oder Anweisungsebene teilen - können Sie sich überhaupt nicht auf die Sitzungseinstellung verlassen.

  • Auth_type =hba. Vor 1.7 war das große Problem mit pgbouncer das Fehlen einer hostbasierten Authentifizierung – „Postgres-Firewall“. Natürlich hatten Sie es immer noch für Postgres-Cluster-Verbindungen, aber pgbouncer war für jede Quelle „offen“. Jetzt können wir dieselbe hba.conf verwenden, um Verbindungen für Host/DB/Benutzer basierend auf dem Verbindungsnetzwerk zu begrenzen.

  • connect_query wird nicht bei jeder Client-„Verbindung“ zu pgbouncer ausgeführt, sondern wenn pgbouncer eine Verbindung zu einer Postgres-Instanz herstellt. Daher können Sie es nicht zum Festlegen oder Überschreiben von „Standard“-Einstellungen verwenden. Im Sitzungsmodus beeinflussen sich andere Sitzungen nicht gegenseitig, und beim Trennen der Verbindung verwirft das Zurücksetzen der Abfrage alle - Sie müssen sich also nicht damit herumschlagen. Im Transaktions-Pooling-Modus würden Sie hoffen, es für Einstellungen zu verwenden, die fälschlicherweise von anderen Sitzungen festgelegt wurden, aber es wird leider nicht funktionieren. Z.B. Sie möchten vorbereitete Anweisungen zwischen „Sitzungen“ im Transaktionsmodus teilen, also setzen Sie etwas wie

    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;'

    und tatsächlich - jeder neue Client sieht die vorbereiteten Anweisungen (es sei denn, Sie haben server_reset_query_always auf on gelassen, also verwirft pgbouncer es beim Commit). Aber wenn ein Client DISCARD s ausführt; in seiner Sitzung wirkt es sich auf alle Clients in dieser Verbindung aus und neue Clients, die sich damit verbinden, sehen keine vorbereiteten Anweisungen mehr. Aber wenn Sie einige Anfangseinstellungen für Postgres-Verbindungen haben möchten, die von pgbouncer kommen, dann ist dies der richtige Ort.

  • application_name_add_host wurde in 1.6 hinzugefügt, es hat ähnliche Einschränkungen. Es „legt“ die Client-IP auf „application_name“, sodass Sie Ihre fehlerhafte Abfragequelle leicht erhalten können, aber es wird leicht überschrieben, indem Sie einfach „application_name TO“ „wasn’t me“ setzen; Trotzdem können Sie dies mit Ansichten „heilen“ – folgen Sie diesem Beitrag, um die Idee zu bekommen, oder verwenden Sie sogar diese kurze Anleitung. Die Grundidee ist, Kunden zu zeigen; zeigt die Client-IP an, sodass Sie sie bei jeder Auswahl von pg_stat_activity direkt aus der pgbouncer-Datenbank abfragen können, um zu prüfen, ob sie zurückgesetzt wurde. Aber natürlich ist eine einfache Einstellung viel einfacher und gemütlicher. Obwohl es das Ergebnis nicht garantiert ...

  • pool_mode kann sowohl als Standard, pro Datenbank als auch pro Benutzer angegeben werden - was ihn sehr flexibel macht. Das Mischen von Modi macht pgbouncer äußerst effektiv für das Pooling. Dies ist eine leistungsstarke Funktion, aber man muss vorsichtig sein, wenn man sie benutzt. Oft verwenden Benutzer es, ohne die Ergebnisse zu verstehen, zu absolut atomaren Mischungen von pro Transaktion/pro Sitzung/pro Benutzer/pro Datenbank/globalen Einstellungen, die für denselben Benutzer oder dieselbe Datenbank aufgrund der unterschiedlichen Pooling-Modi mit pgbouncer unterschiedlich funktionieren. Dies ist die Streichholzschachtel, die Sie Kindern nicht ohne Aufsicht geben. Auch viele andere Optionen sind als Standard und pro Datenbank und pro Benutzer konfigurierbar.

  • Bitte nehmen Sie es nicht wörtlich, aber Sie können verschiedene Abschnitte von ini mit SET und ALTER „vergleichen“:SET LOCAL wirkt sich auf Transaktionen aus und ist gut zu verwenden, wenn poll_mode=transaction , SET SESSION wirkt sich auf Sitzungen aus und kann sicher verwendet werden, wenn poll_mode=session , ALTER USER SET wirkt sich auf Rollen aus und stört den pgbouncer.ini-Teil des Abschnitts [users], ALTER DATABASE SET betrifft Datenbanken und stört den pgbouncer.ini-Teil des Abschnitts [databases], ALTER SYSTEM SET oder das Bearbeiten von postgres.conf wirkt sich global auf die Standardwerte aus und ist vergleichbar mit dem Standardabschnitt von pgbouncer.ini.

  • Noch einmal - verwenden Sie den Pool-Modus verantwortungsbewusst. Vorbereitete Anweisungen oder sitzungsweite Einstellungen werden im Transaktions-Pooling-Modus ein Durcheinander sein. Dasselbe wie eine SQL-Transaktion im Statement-Pooling-Modus keinen Sinn macht. Wählen Sie einen geeigneten Pooling-Modus für geeignete Verbindungen. Eine gute Praxis ist das Erstellen von Rollen mit der Idee, dass:

    • Einige führen nur schnelle Auswahlen aus und können sich daher eine Sitzung ohne Transaktionen für hundert gleichzeitige kleine unwichtige Auswahlen teilen.
    • Einige Rollenmitglieder sind sicher für die Parallelität auf Sitzungsebene und verwenden IMMER Transaktionen. So können sie sicher mehrere Sitzungen für Hunderte gleichzeitiger Transaktionen freigeben.
    • Einige Rollen sind einfach zu chaotisch oder kompliziert, um ihre Sitzung mit anderen zu teilen. Sie verwenden also den Session-Pooling-Modus für sie, um Verbindungsfehler zu vermeiden, wenn alle „Slots“ bereits belegt sind.
  • Verwenden Sie es nicht anstelle von HAProxy oder einem anderen Load Balancer. Trotz der Tatsache, dass pgbouncer über mehrere konfigurierbare Funktionen verfügt, die adressieren, was ein Load Balancer adressiert, wie dns_max_ttl, und Sie eine DNS-Konfiguration dafür einrichten können, verwenden die meisten Produktumgebungen HAProxy oder einen anderen Load Balancer für HA. Dies liegt daran, dass HAProxy wirklich gut im Load-Balancing zwischen Live-Servern in Round-Robin-Manier ist, besser als pgbouncer. Obwohl pgbouncer besser für das Pooling von Postgres-Verbindungen geeignet ist, könnte es besser sein, einen kleinen Daemon zu verwenden, der eine Aufgabe perfekt ausführt, anstatt einen größeren, der zwei Aufgaben erledigt, aber schlechter.

  • Konfigurationsänderungen können schwierig sein. Einige Änderungen an pgbouncer.ini erfordern einen Neustart (listen_port und dergleichen), während andere wie admin_users ein Neuladen oder SIGHUP erfordern. Änderungen in auth_hba_file müssen neu geladen werden, während Änderungen an auth_file dies nicht tun.

Die extrem kurze Übersicht der Einstellungen oben ist durch das Format begrenzt. Ich lade Sie ein, einen Blick auf die vollständige Liste zu werfen. Pgbouncer ist die Art von Software mit sehr wenigen "langweiligen Einstellungen" - sie alle haben ein riesiges Potenzial und sind von erstaunlichem Interesse.

Laden Sie noch heute das Whitepaper PostgreSQL-Verwaltung und -Automatisierung mit ClusterControl herunterErfahren Sie, was Sie wissen müssen, um PostgreSQL bereitzustellen, zu überwachen, zu verwalten und zu skalierenLaden Sie das Whitepaper herunter

Und schließlich, von einer kurzen enthusiastischen Rezension zu etwas überzugehen, wo Sie vielleicht weniger zufrieden sind – die Installation. Der Prozess ist in diesem Abschnitt der Dokumentation klar beschrieben. Die einzige beschriebene Option ist das Erstellen aus Git-Quellen. Aber jeder weiß, dass es Pakete gibt! Versuchen Sie beide beliebtesten:

sudo yum install pgbouncer
sudo apt-get install pgbouncer

kann arbeiten. Aber manchmal muss man einen zusätzlichen Schritt machen. Wenn z. B. kein Pgbouncer-Paket verfügbar ist, versuchen Sie dies.

Oder sogar:

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

Natürlich hilft das Hinzufügen von pgdg zu /etc/yum.repos.d/ nicht mehr. Weder --skip-broken noch rpm -Va --nofiles --nodigest. Ein einfaches

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

wäre zu einfach. Sie müssen also libevent2 selbst erstellen, was Sie wieder in die Position bringt, in der Sie Dinge selbst kompilieren müssen. Entweder ist es pgbouncer oder eine seiner Abhängigkeiten.

Auch hier - zu tief mit den Besonderheiten der Installation zu graben, ist nicht möglich. Sie sollten wissen, dass Sie eine große Chance haben, es als Paket zu installieren.

Schließlich kommen immer wieder Fragen wie „Warum Postgres keinen nativen Session-Pooler anbietet“. Es gibt sogar ganz frische Anregungen und Gedanken dazu. Aber bisher ist der beliebteste Ansatz hier die Verwendung von pgbouncer.