sql >> Database teknologi >  >> RDS >> PostgreSQL

En guide til brug af pgBouncer til PostgreSQL

Når du læser PostgreSQL for at komme i gang, ser du linjen:"PostgreSQL-serveren kan håndtere flere samtidige forbindelser fra klienter. For at opnå dette starter den (“gafler”) en ny proces for hver forbindelse. Fra det tidspunkt kommunikerer klienten og den nye serverproces uden indblanding fra den originale postgres-proces. Masterserverprocessen kører således altid og venter på klientforbindelser, hvorimod klient- og tilhørende serverprocesser kommer og går.

Genial idé. Og alligevel betyder det, at hver ny forbindelse spinder en ny proces, reserverer RAM og muligvis bliver for tung med flere sessioner. For at undgå problemer har postgres max_connections indstilling med standard 100 forbindelser. Selvfølgelig kan du øge det, men en sådan handling ville kræve genstart (pg_settings.context er '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
Nogle spændende læsninger PgBouncer-brug Hvad er meningen med at hoppe? PgBouncer Changelog Indlæg indeholdende 'pgbouncer' på Stack Overflow Indlæg tagget 'pgbouncer' på 2ndQuadrant

Og selv efter at have øget - på et tidspunkt kan du have brug for flere forbindelser (naturligvis presserende som altid på kørende prod). Hvorfor er det så ubehageligt at øge det? For hvis det var behageligt, ville du sandsynligvis ende med ukontrolleret spontan forøgelse af antallet, indtil klyngen begynder at halte. Det betyder, at gamle forbindelser er langsommere - så de tager længere tid, så du har brug for endnu mere og mere nyt. For at undgå en sådan mulig lavine og tilføje en vis fleksibilitet, har vi superuser_reserved_connections - for at kunne forbinde og løse problemer med SU når max_connections er opbrugt. Og vi ser åbenbart behovet for en eller anden forbindelsespooler. Da vi ønsker, at nye forbindelseskandidater skal vente i en kø i stedet for at fejle med undtagelse FATAL:beklager, for mange kunder allerede og ikke risikere postmesteren.

Forbindelsespooling tilbydes på et eller andet niveau af mange populære "klienter". Du kan bruge det med jdbc i et stykke tid. For nylig tilbød node-postgres sin egen node-pg-pool. Mere eller mindre er implementeringen enkel (som ideen er):pooler starter forbindelserne mod databasen og beholder dem. Klienten, der opretter forbindelse til db, får kun en "delt" eksisterende forbindelse, og efter at den er lukket, går forbindelsen tilbage til puljen. Vi har også meget mere sofistikeret software, som pgPool. Og alligevel er pgbouncer et ekstremt populært valg til opgaven. Hvorfor? For det gør kun pooling-delen, men gør det rigtigt. Det er gratis. Det er ret nemt at sætte op. Og du møder det hos de fleste største tjenesteudbydere som anbefalet eller brugt, f.eks. citusdata, aws, heroku og andre højt respekterede ressourcer.

Så lad os se nærmere på, hvad det kan, og hvordan du bruger det. I min opsætning bruger jeg standard pool_mode =transaktion ([pgbouncer] sektion), som er et meget populært valg. På denne måde sætter vi ikke bare forbindelserne i kø, der overstiger max_connections, men genbruger snarere sessioner uden at vente på, at den tidligere forbindelse lukker:

[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

Kort oversigt over de mest populære indstillinger og tips og tricks:

  • server_reset_query er meget praktisk og vigtig. I sessionspooling-tilstand "sletter" den tidligere sessions "artefakter". Ellers ville du have problemer med samme navne for forberedte udsagn, sessionsindstillinger, der påvirker næste sessioner og så videre. Standarden er DISCARD ALL, som "nulstiller" alle sessionstilstande. Alligevel kan du vælge mere sofistikerede værdier, f.eks. NULSTIL ALLE; AFDELA ALLE; at glemme kun SET SESSION og forberedte erklæringer, holde TEMP tabeller og planer "delt". Eller det modsatte - du vil måske lave forberedte udtalelser "globale" fra enhver session. En sådan konfiguration er mulig, selvom den er risikabel. Du er nødt til at få pgbouncer til at genbruge sessionen for alle (således gør du enten en meget lille poolstørrelse eller laver sessionerne), hvilket ikke er helt pålideligt. Anyway - det er en nyttig evne. Især i opsætninger, hvor du ønsker, at klientsessioner til sidst (ikke med det samme) ændres til konfigurerede poolede sessionsindstillinger. Meget vigtigt punkt her er session pool mode. Før 1.6 påvirkede denne indstilling også andre pooltilstande, så hvis du stolede på den, skal du bruge den nye indstilling server_reset_query_always =1. Sandsynligvis vil folk på et tidspunkt ønske, at server_reset_query skal være endnu mere fleksibel og konfigurerbar pr. db/brugerpar ( og client_reset_query i stedet). Men i skrivende stund, marts 2018, er det ikke en mulighed. Ideen bag at gøre denne indstilling gyldig som standard kun for sessionstilstand var - hvis du deler forbindelse på transaktions- eller kontoudtogsniveau - kan du slet ikke stole på sessionsindstillingen.

  • Auth_type =hba. Før 1.7 var det store problem med pgbouncer fraværet af værtsbaseret autentificering - "postgres firewall". Selvfølgelig havde du det stadig til postgres-klyngeforbindelse, men pgbouncer var "åben" for enhver kilde. Nu kan vi bruge den samme hba.conf til at begrænse forbindelser for vært/db/bruger baseret på forbindelsesnetværk.

  • connect_query udføres ikke på hver klient-"forbindelse" til pgbouncer, men snarere når pgbouncer opretter forbindelse til en Postgres-instans. Du kan derfor ikke bruge den til at indstille eller tilsidesætte "standard"-indstillinger. I sessionstilstand påvirker andre sessioner ikke hinanden, og ved afbrydelse af forbindelse kasserer nulstillingsforespørgsel alt - så du behøver ikke rode med det. I transaktionspooling-tilstand ville du håbe på at bruge det til indstillinger, der tilsidesætter fejlagtigt indstillet af andre sessioner, men det virker desværre ikke. For eksempel. du vil dele forberedt erklæring mellem "sessioner" i transaktionstilstand, så du indstiller noget lignende

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

    og faktisk - hver ny klient ser de forberedte sætninger (medmindre du lod server_reset_query_always være tændt, så pgbouncer kasserer det ved commit). Men hvis en klient kører DISCARD s; i sin session påvirker det alle klienter på denne forbindelse, og nye klienter, der opretter forbindelse til det, vil ikke længere se forberedte erklæringer. Men hvis du vil have nogle indledende indstillinger for postgres-forbindelser, der kommer fra pgbouncer, så er dette stedet.

  • application_name_add_host blev tilføjet i 1.6, den har lignende begrænsninger. Det "sætter" klientens IP til application_name, så du nemt kan få din dårlige forespørgselskilde, men er let tilsidesat af simpelt sæt application_name TIL 'wasn''t me'; Du kan stadig "helbrede" dette ved at bruge visninger - følg dette indlæg for at få ideen eller brug endda disse korte instruktioner. Grundlæggende ideen er, at vise kunder; vil vise klientens IP, så du kan forespørge det direkte fra pgbouncer-databasen på hvert valg fra pg_stat_activity for at kontrollere, om det er nulstillet. Men selvfølgelig er det meget enklere og hyggeligere at bruge en enkel indstilling. Selvom det ikke garanterer resultatet...

  • pool_mode kan angives både som standard, pr. database og pr. bruger - hvilket gør det meget fleksibelt. Blandingstilstande gør pgbouncer ekstremt effektiv til pooling. Dette er en kraftfuld funktion, men man skal være forsigtig, når man bruger den. Ofte bruger brugere det uden at forstå resultaterne til absolut atomiske blandinger af pr. transaktion/pr. session/pr. bruger/pr. database/globale indstillinger, der fungerer forskelligt for den samme bruger eller database, på grund af de forskellige pooling-tilstande med pgbouncer. Dette er æsken med tændstikker, du ikke giver til børn uden opsyn. Også mange andre muligheder kan konfigureres til standard og pr. db og pr. bruger.

  • Tag det ikke bogstaveligt, men du kan "sammenligne" forskellige sektioner af ini med SET og ALTER:SET LOCAL påvirker transaktioner og er god at bruge, når poll_mode=transaktion , SET SESSION påvirker sessioner og er sikker at bruge, når poll_mode=session , ALTER USER SET påvirker roller og vil forstyrre pgbouncer.ini del af sektion [brugere], ALTER DATABASE SET påvirker databaser og vil forstyrre pgbouncer.ini del af sektion [databaser], ALTER SYSTEM SET eller redigering af postgres.conf påvirker globalt standardindstillinger og er i kraft sammenlignelig med standardafsnittet på pgbouncer.ini.

  • Endnu en gang - brug pooltilstand ansvarligt. Forberedte erklæringer eller indstillinger for hele sessionen vil være et rod i transaktionspooling-tilstand. Samme som SQL-transaktion giver ingen mening i sætningspooling-tilstand. Vælg en passende pooling-tilstand for passende forbindelser. En god praksis er at skabe roller med den idé, at:

    • nogle vil kun køre hurtige valg, og kan således dele en session uden transaktioner for hundrede af samtidige små, ikke vigtige valg.
    • Nogle rollemedlemmer er sikre for samtidighed på sessionsniveau og bruger ALTID transaktioner. De kan således trygt dele flere sessioner for hundredvis af samtidige transaktioner.
    • Nogle roller er bare for rodet eller komplicerede til at dele deres session med andre. Så du bruger sessionspooling-tilstand for dem for at undgå fejl ved forbindelsen, når alle "slots" allerede er taget.
  • Brug det ikke i stedet for HAProxy eller en anden load balancer. På trods af at pgbouncer har flere konfigurerbare funktioner, der adresserer, hvad en load balancer adresserer, såsom dns_max_ttl, og du kan konfigurere en DNS-konfiguration til det, bruger de fleste prod-miljøer HAProxy eller en anden load balancer til HA. Dette skyldes, at HAProxy er rigtig god til belastningsbalancering på tværs af live-servere på round robin-måde, bedre end pgbouncer. Selvom pgbouncer er bedre til postgres-forbindelsespooling, kan det være bedre at bruge en lille dæmon, der perfekt udfører én opgave, i stedet for en større, der udfører to opgaver, men værre.

  • Konfigurationsændringer kan være vanskelige. Nogle ændringer af pgbouncer.ini kræver genstart (listen_port og sådan), mens andre såsom admin_users kræver genindlæsning eller SIGHUP. Ændringer i auth_hba_file kræver genindlæsning, mens ændringer til auth_file ikke gør det.

Den ekstremt korte oversigt over indstillinger ovenfor er begrænset af formatet. Jeg inviterer dig til at tage et kig på den komplette liste. Pgbouncer er den slags software med meget små mængder "kedelige indstillinger" - de har alle et kæmpe potentiale og er af fantastisk interesse.

Download Whitepaper Today PostgreSQL Management &Automation med ClusterControlFå flere oplysninger om, hvad du skal vide for at implementere, overvåge, administrere og skalere PostgreSQLDownload Whitepaper

Og til sidst, at gå fra en kort begejstret anmeldelse til noget, hvor du måske er mindre glad - installationen. Processen er tydeligt beskrevet i dette afsnit af dokumentation. Den eneste beskrevne mulighed er at bygge fra git-kilder. Men alle ved, at der er pakker! Prøver begge mest populære:

sudo yum install pgbouncer
sudo apt-get install pgbouncer

kan arbejde. Men nogle gange skal du tage et ekstra skridt. Hvis der f.eks. ikke er nogen pgbouncer-pakke tilgængelig, så prøv dette.

Eller endda:

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

Selvfølgelig hjælper det ikke længere at tilføje pgdg til /etc/yum.repos.d/. Hverken --skip-broken eller rpm -Va --nofiles --nodigest. En simpel

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

ville være for let. Så du skal selv bygge libevent2, hvilket bringer dig tilbage til den position, hvor du selv skal kompilere tingene. Enten er det pgbouncer eller en af ​​dets afhængigheder.

Igen - at grave for dybt med installationens særlige forhold er uden for rækkevidde. Du skal vide, at du har en stor chance for at installere det som pakke.

Til sidst - spørgsmål som "hvorfor postgres ikke tilbyder en native session pooler" kommer igen og igen. Der er endda meget friske forslag og tanker om det. Men indtil videre er den mest populære tilgang her at bruge pgbouncer.


  1. Hvad er det bedste PostgreSQL High Availability Framework? PAF vs. repmgr vs. Patroni Infographic

  2. SQL Server-systemdatabaser – Tempdb-vedligeholdelsen

  3. Hvordan Cosh() virker i PostgreSQL

  4. 7 muligheder for at aktivere rør (||) som sammenkædningsoperatør i MariaDB