Pooling van verbindingen is een eenvoudige maar effectieve manier om de prestaties van uw apps te verbeteren en de belasting van uw PostgreSQL-servers te verminderen. Lees verder voor meer informatie over het gebruik van PgBouncer om PostgreSQL-verbindingen te poolen.
Waarom Connection Pooling?
PostgreSQL heeft een nogal zware architectuur voor het afhandelen van verbindingen. Voor elke inkomende verbinding, de postmaster (de belangrijkste Postgres-daemon) vorkt een nieuw proces uit (conventioneel een backend genoemd) ) om ermee om te gaan. Hoewel dit ontwerp zorgt voor betere stabiliteit en isolatie, is het niet bijzonder efficiënt in het omgaan met kortstondige verbindingen. Een nieuwe Postgres-clientverbinding omvat het instellen van TCP, het maken van processen en het initialiseren van de back-end - die allemaal kostbaar zijn in termen van tijd en systeembronnen.
Dit is natuurlijk alleen een probleem als verbindingen te vaak worden gemaakt en zonder hergebruik worden weggegooid. Helaas is het niet ongebruikelijk om een cluster van webknooppunten te hebben met applicaties die zijn geschreven in PHP of andere soortgelijke talen die eenmaal per paginalading verbinding met de database moeten maken. Batchjobs die snel veel verbindingen maken, komen ook veel voor. Gebruik maken van connectionpooling in dergelijke scenario's kan de belasting van uw PostgreSQL-server drastisch worden verminderd en de querylatenties aanzienlijk worden verbeterd.
Bij pooling van verbindingen maken de clients verbinding met een proxyserver die een reeks directe verbindingen met de echte PostgreSQL-server onderhoudt. Meestal realiseren de clients zich niet (en zouden ze niet moeten) dat ze verbonden zijn met een proxyserver in plaats van met de eigenlijke server. De proxy kan op hetzelfde knooppunt draaien als de client (bijvoorbeeld op elk webknooppunt), in welk geval de clients verbinding kunnen maken met de proxy via Unix-domeinsockets die een zeer lage verbindingsoverhead hebben. Zelfs als de proxy zich op een ander knooppunt bevindt en de client een TCP-verbinding nodig heeft om de proxy te bereiken, kan de overhead van een nieuwe Postgres-backend worden vermeden.
Wat is PgBouncer?
PgBouncer is een open-source, lichtgewicht, enkel-binaire verbindingspooler voor PostgreSQL. Het kan verbindingen met een of meer databases (op mogelijk verschillende servers) poolen en clients bedienen via TCP- en Unix-domeinsockets.
PgBouncer onderhoudt een pool van verbindingen voor elke unieke gebruiker, databasepaar. Het is meestal geconfigureerd om een van deze verbindingen uit te delen aan een nieuwe inkomende clientverbinding en deze terug te sturen naar de pool wanneer de client de verbinding verbreekt. U kunt PgBouncer configureren om agressiever te poolen, zodat het de verbinding kan ophalen en teruggeven aan de pool bij transactie- of verklaringsgrenzen in plaats van verbindingsgrenzen. Daar zijn echter enkele potentieel ongewenste gevolgen aan verbonden.
Je zou PgBouncer moeten kunnen installeren met de pakketbeheerder van je distro:
# RedHat/CentOS/..
$ sudo yum install pgbouncer
# Debian/Ubuntu/..
$ sudo apt-get install pgbouncer
Het is ook beschikbaar via de standaard Postgres APT- en YUM-repo's, die kunnen worden gebruikt als de pakketten van je distro oud of kapot zijn.
PgBouncer vertrouwt op een hoofdconfiguratiebestand, meestal opgeslagen als/etc/pgbouncer/pgbouncer.ini
. Je kunt pgbouncer aanroepen als een systemd-service, of het gewoon uitvoeren, zelfs zonder superuser-privileges met het pad naar dit configuratiebestand.
Laten we, om er een draai aan te geven, een database db1 en een gebruiker user1 op onze server maken:
$ sudo -u postgres psql
psql (10.6 (Debian 10.6-1.pgdg90+1))
Type "help" for help.
postgres=# create user user1 password 'user1pass';
CREATE ROLE
postgres=# create database db1 owner user1;
CREATE DATABASE
postgres=#
Clients zullen verbinding maken met de database db1
met de gebruikersnaam user1
andpassword user1pass
. Ons doel is om de clients verbinding te laten maken met PgBouncer, die de verbindingen naar de eigenlijke server zal proxyen en poolen.
Laten we nu een bestand (overal) maken met deze inhoud:
[databases]
db1 = host=localhost dbname=db1
[pgbouncer]
listen_addr = 127.0.0.1
listen_port = 16432
auth_file = userlist.txt
We moeten ook een "userlist.txt"-bestand maken in dezelfde map, met de gebruikersnaam en (gehashte) wachtwoorden van gebruikers die PgBouncer toestaat om verbinding te maken. Maak "userlist.txt" met de volgende inhoud:
"user1" "md5638b81c77071ea624d1ad4adb1433540"
De tweede waarde is de MD5 van "user1passuser1", voorafgegaan door "md5". Dit is de gebruikelijke Postgres-conventie.
Laten we nu PgBouncer op de voorgrond starten:
$ /usr/sbin/pgbouncer pgbouncer.ini
2019-02-05 11:46:18.011 10033 LOG file descriptor limit: 1024 (H:1048576), max_client_conn: 100, max fds possible: 130
2019-02-05 11:46:18.012 10033 LOG listening on 127.0.0.1:16432
2019-02-05 11:46:18.013 10033 LOG listening on unix:/tmp/.s.PGSQL.16432
2019-02-05 11:46:18.014 10033 LOG process up: pgbouncer 1.9.0, libevent 2.0.21-stable (epoll), adns: c-ares 1.12.0, tls: OpenSSL 1.1.0j 20 Nov 2018
We hebben nu een PgBouncer gestart die luistert op 127.0.0.1 TCP-poort 16432, evenals op de Unix-domeinsocket /tmp/.s.PGSQL.16432
. De enige "database" die beschikbaar is op deze proxyserver is db1
. De enige gebruiker die verbinding kan maken met deze server is user1
. Laten we proberen verbinding te maken met psql
:
$ psql -U user1 -p 16432 -h localhost db1
Password for user user1:
psql (10.6 (Debian 10.6-1.pgdg90+1))
Type "help" for help.
db1=> select inet_server_addr(), inet_server_port();
inet_server_addr | inet_server_port
------------------+------------------
127.0.0.1 | 5432
(1 row)
db1=>
De client (psql) maakt met succes verbinding met localhost:16432, maar je kunt zien dat de verbinding daadwerkelijk wordt geproxy naar localhost:5432.
U kunt een paar keer proberen de verbinding te verbreken en opnieuw verbinding te maken en vervolgens controleren hoeveel verbindingen er nog zijn op de eigenlijke server:
postgres=# select count(*) from pg_stat_activity
postgres-# where datname='db1' and usename='user1';
count
-------
1
(1 row)
PgBouncer verbreekt de daadwerkelijke verbinding niet wanneer de client de verbinding verbreekt. U kunt de minimale, maximale en gereserveerde verbindingen configureren die PgBouncer voor elke pool in het configuratiebestand zal onderhouden.
PgBouncer implementeren
Waar installeer en voer je PgBouncer uit? Er zijn verschillende antwoorden, met verschillende voordelen:
- Op het Postgres-serverknooppunt :U kunt het naast de PostgreSQLserver zelf installeren, op hetzelfde knooppunt. De clients maken verbinding met de PgBouncer-poort in plaats van met de Postgres-poort. Dit heeft het effect van een "verbeterde" Postgres die intern verbindingspooling uitvoert. U hoeft ook maar één kopie van de configuratiebestanden voor PgBouncer te onderhouden. Aan de andere kant houdt dit in dat er ook iets anders wordt uitgevoerd op het PostgreSQL-serverknooppunt, wat misschien niet eenvoudig of toegestaan is (firewalls, beleid) of zelfs mogelijk (AWSRDS).
- Op clientknooppunten :U kunt PgBouncer in elk clientknooppunt installeren, bijvoorbeeld elk webknooppunt voert Apache en PHP uit, en de PHP-scripts maken verbinding met de localPgBouncer. Dit heeft het voordeel dat de serverconfiguratie niet hoeft te worden verstoord, en de poolconfiguratie kan worden gebruikt om de serverbelasting voorspelbaar te houden. Aan de andere kant, als het aantal clientknooppunten enorm is, of veel kan variëren, afhankelijk van de belasting/ verkeer kan de server snel overbelast raken.
- Als een op zichzelf staand cluster :De derde optie om een cluster van onafhankelijke, staatloze PgBouncer-knooppunten te hebben, met als front een TCP-load balancer zoals HAProxy. Deze configuratie, hoewel ingewikkelder dan de andere twee opties, biedt maximale controle en configureerbaarheid.
Beheer
Met PgBouncer kunnen gebruikers die als admin zijn gemarkeerd, verbinding maken met een virtuele database genaamd "pgbouncer" en opdrachten geven om de server te besturen en statistieken te bekijken. Laten we om dit te proberen eerst "gebruiker1" markeren als beheerder door het bestand pgbouncer.ini te wijzigen:
[databases]
db1 = host=localhost dbname=db1
[pgbouncer]
listen_addr = 127.0.0.1
listen_port = 16432
auth_file = userlist.txt
admin_users = user1
Nu kan gebruiker1 verbinding maken met de database met de naam "pgbouncer":
$ psql -U user1 -p 16432 -h localhost pgbouncer
Password for user user1:
psql (10.6 (Debian 10.6-1.pgdg90+1), server 1.9.0/bouncer)
Type "help" for help.
pgbouncer=#
Vanaf hier kunt u verschillende dingen doen, zoals het in- of uitschakelen van een bepaalde database, het inspecteren en opnieuw laden van de configuratie, en meer:
pgbouncer=# RELOAD;
RELOAD
pgbouncer=# DISABLE db1;
DISABLE
pgbouncer=# ENABLE db1;
ENABLE
pgbouncer=# SHOW FDS;
fd | task | user | database | addr | port | cancel | link | client_encoding | std_strings | datestyle | timezone | pa
----+--------+-------+----------+-----------+-------+----------------+------+-----------------+-------------+-----------+-----------+---
6 | pooler | | | 127.0.0.1 | 16432 | 0 | 0 | | | | |
7 | pooler | | | unix | 16432 | 0 | 0 | | | | |
9 | server | user1 | db1 | 127.0.0.1 | 5432 | 45404395804679 | 0 | UTF8 | on | ISO, MDY | localtime |
(3 rows)
Bewaking
Er zijn ook opdrachten om verschillende statistieken over de PgBouncer te tonen, waaronder:
- Statistieken per database over de duur van de zoekopdracht, de wachttijd van de klant, het netwerkgebruik, het aantal transacties
- Statistieken per pool over het aantal actieve en wachtende clients, inactieve en gebruikte serververbindingen
Statistieken worden opgehaald met "SHOW xyz" stijlcommando's, zoals deze om gerelateerde statistieken op te halen:
pgbouncer=# SHOW POOLS;
-[ RECORD 1 ]---------
database | db1
user | user1
cl_active | 0
cl_waiting | 0
sv_active | 0
sv_idle | 0
sv_used | 1
sv_tested | 0
sv_login | 0
maxwait | 0
maxwait_us | 0
pool_mode | session
-[ RECORD 2 ]---------
database | pgbouncer
user | pgbouncer
cl_active | 1
cl_waiting | 0
sv_active | 0
sv_idle | 0
sv_used | 0
sv_tested | 0
sv_login | 0
maxwait | 0
maxwait_us | 0
pool_mode | statement
Verder lezen
De PgBouncer-startpagina bevat meer details over alle verschillende functies en configuratie-opties van PgBouncer.
- PgBouncer-startpagina
- PgBouncer GitHub-opslagplaats
- Postgres Wiki heeft informatie over pooling van verbindingen
- Pgpool is een andere optie voor pooling van verbindingen