sql >> Databasteknik >  >> RDS >> PostgreSQL

En guide till att använda pgBouncer för PostgreSQL

När du läser PostgreSQL för att komma igång ser du raden:"PostgreSQL-servern kan hantera flera samtidiga anslutningar från klienter. För att uppnå detta startar den (“gafflar”) en ny process för varje anslutning. Från den tidpunkten kommunicerar klienten och den nya serverprocessen utan ingripande av den ursprungliga postgres-processen. Således är huvudserverprocessen alltid igång och väntar på klientanslutningar, medan klient- och associerade serverprocesser kommer och går.

Brilliant idé. Och ändå betyder det att varje ny anslutning snurrar en ny process, reserverar RAM och kanske blir för tungt med flera sessioner. För att undvika problem har postgres max_connections inställning med standard 100 anslutningar. Naturligtvis kan du öka den, men en sådan åtgärd skulle kräva omstart (pg_settings.context är '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
Några spännande läsningar PgBouncer-användning Vad är poängen med att studsa? PgBouncer Changelog Inlägg som innehåller 'pgbouncer' på Stack Overflow Inlägg taggade 'pgbouncer' på 2ndQuadrant

Och även efter ökning - någon gång kan du behöva fler anslutningar (naturligtvis akut som alltid på löpande prod). Varför är det så obehagligt att öka det? För om det var bekvämt, skulle du förmodligen sluta med okontrollerad spontan ökning av antalet tills klustret börjar släpa. Det betyder att gamla anslutningar är långsammare - så de tar längre tid, så du behöver ännu mer och mer nytt. För att undvika en sådan möjlig lavin och lägga till lite flexibilitet har vi superuser_reserved_connections - för att kunna koppla upp och fixa problem med SU när max_connections är slut. Och vi ser uppenbarligen behovet av någon anslutningspoolare. Eftersom vi vill att nya anslutningskandidater ska vänta i en kö istället för att misslyckas med undantag FATAL:ledsen, för många kunder redan och riskerar inte postmästaren.

Anslutningspoolning erbjuds på någon nivå av många populära "klienter". Du kan använda den med jdbc ett bra tag. Nyligen erbjöd node-postgres sin egen nod-pg-pool. Mer eller mindre är implementeringen enkel (som tanken är):pooler startar kopplingarna mot databasen och behåller dem. Klienten som ansluter till db får bara en "delad" befintlig anslutning och efter att den stängts går anslutningen tillbaka till poolen. Vi har också mycket mer sofistikerad programvara, som pgPool. Och ändå är pgbouncer ett extremt populärt val för uppgiften. Varför? För det gör bara pooldelen, men gör det rätt. Det är gratis. Det är ganska enkelt att ställa in. Och du möter det hos de flesta största tjänsteleverantörer som rekommenderas eller används, t.ex. citusdata, aws, heroku och andra högt respekterade resurser.

Så låt oss titta närmare på vad det kan och hur du använder det. I min inställning använder jag standard pool_mode =transaktion (sektionen [pgbouncer]) vilket är ett mycket populärt val. På så sätt köar vi inte bara anslutningarna som överstiger max_connections, utan återanvänder snarare sessioner utan att vänta på att den tidigare anslutningen ska stängas:

[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 översikt över de mest populära inställningarna och tips och tricks:

  • server_reset_query är väldigt praktisk och viktig. I sessionspoolningsläge "torkar" den tidigare sessions "artefakter". Annars skulle du få problem med samma namn för förberedda uttalanden, sessionsinställningar som påverkar nästa sessioner och så vidare. Standard är DISCARD ALL, som "återställer" alla sessionstillstånd. Ändå kan du välja mer sofistikerade värden, t.ex. ÅTERSTÄLL ALLA; AVDELA ALLA; att bara glömma SET SESSION och förberedda uttalanden, att hålla TEMP-tabeller och planer "delade". Eller tvärtom - du kanske vill göra förberedda uttalanden "globala" från vilken session som helst. Sådan konfiguration är genomförbar, även om den är riskabel. Du måste få pgbouncer att återanvända sessionen för alla (och på så sätt göra antingen en mycket liten poolstorlek eller göra sessionerna lavinerade), vilket inte är helt tillförlitligt. Hur som helst - det är en användbar förmåga. Speciellt i inställningar där du vill att klientsessioner så småningom (inte omedelbart) ändras till konfigurerade poolade sessionsinställningar. En mycket viktig punkt här är sessionspoolläget. Före 1.6 påverkade den här inställningen även andra poollägen, så om du litade på den måste du använda den nya inställningen server_reset_query_always =1. Förmodligen kommer folk någon gång att vilja att server_reset_query ska vara ännu mer flexibel och konfigurerbar per db/användarpar ( och client_reset_query istället). Men när det nu skrivs, mars 2018, är det inte ett alternativ. Tanken bakom att göra denna inställning giltig som standard endast för sessionsläge var - om du delar anslutning på transaktions- eller kontoutdragsnivå - kan du inte förlita dig på sessionsinställningen alls.

  • Auth_type =hba. Före 1.7 var det stora problemet med pgbouncer frånvaron av värdbaserad autentisering - "postgres firewall". Naturligtvis hade du det fortfarande för postgres-klusteranslutning, men pgbouncer var "öppen" för vilken källa som helst. Nu kan vi använda samma hba.conf för att begränsa anslutningar för värd/db/användare baserat på anslutningsnätverk.

  • connect_query utförs inte på varje klient-"anslutning" till pgbouncer, utan snarare när pgbouncer ansluter till en Postgres-instans. Du kan alltså inte använda den för att ställa in eller åsidosätta "standardinställningar". I sessionsläge påverkar inte andra sessioner varandra och vid frånkoppling kasserar återställningsfrågan allt - så du behöver inte bråka med det. I transaktionspoolningsläge skulle du hoppas kunna använda det för inställningar som åsidosätter felaktigt inställda av andra sessioner, men det kommer tyvärr inte att fungera. T.ex. du vill dela förberedda uttalanden mellan "sessioner" i transaktionsläge, så du ställer in något liknande

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

    och faktiskt - varje ny klient ser de förberedda satserna (såvida du inte lämnade server_reset_query_always till på, så pgbouncer kasserar det vid commit). Men om någon klient kör DISCARD s; i sin session påverkar den alla klienter på den här anslutningen och nya klienter som ansluter till den kommer inte att se förberedda uttalanden längre. Men om du vill ha en initial inställning för postgres-anslutningar som kommer från pgbouncer, då är det här platsen.

  • application_name_add_host lades till i 1.6, den har liknande begränsningar. Det "sätter" klientens IP till application_name, så att du enkelt kan få din dåliga frågekälla, men det åsidosätts enkelt av en enkel uppsättning application_name TO 'wasn''t me'; Du kan fortfarande "läka" detta med visningar - följ det här inlägget för att få idén eller använd till och med dessa korta instruktioner. I grund och botten tanken är att visa kunder; kommer att visa klientens IP, så att du kan fråga den direkt från pgbouncer-databasen på varje val från pg_stat_activity för att kontrollera om den är återställd. Men att använda en enkel inställning är naturligtvis mycket enklare och mysigare. Även om det inte garanterar resultatet...

  • pool_mode kan anges både som standard, per databas och per användare - vilket gör det mycket flexibelt. Blandningslägen gör pgbouncer extremt effektiv för pooling. Detta är en kraftfull funktion, men man måste vara försiktig när man använder den. Ofta använder användare det utan att förstå resultaten för att absolut atomära mixar av per transaktion/per session/per användare/per databas/globala inställningar fungerar annorlunda för samma användare eller databas, på grund av de olika poolningslägena med pgbouncer. Detta är lådan med tändstickor du inte ger till barn utan tillsyn. Även många andra alternativ är konfigurerbara för standard och per db och per användare.

  • Ta det inte bokstavligt, men du kan "jämföra" olika delar av ini med SET och ALTER:SET LOCAL påverkar transaktioner och är bra att använda när poll_mode=transaktion , SET SESSION påverkar sessioner och är säker att använda när poll_mode=session , ALTER USER SET påverkar roller och kommer att störa pgbouncer.ini del av sektionen [användare], ALTER DATABASE SET påverkar databaser och kommer att störa pgbouncer.ini delen av sektionen [databaser], ALTER SYSTEM SET eller redigering av postgres.conf påverkar globalt standardinställningar och är genom effekt jämförbar med standardavsnittet i pgbouncer.ini.

  • Än en gång - använd poolläget ansvarsfullt. Förberedda uttalanden eller sessionsomfattande inställningar kommer att vara en enda röra i transaktionspoolningsläge. Samma som SQL-transaktion är meningslös i satspoolningsläge. Välj ett lämpligt poolläge för lämpliga anslutningar. En bra praxis är att skapa roller med tanken att:

    • en del kommer bara att köra snabba val, så de kan dela en session utan transaktioner för hundra samtidiga små inte viktiga val.
    • Vissa rollmedlemmar är säkra för samtidighet på sessionsnivå och använder ALLTID transaktioner. Således kan de säkert dela flera sessioner för hundratals samtidiga transaktioner.
    • Vissa roller är alldeles för röriga eller komplicerade för att dela sin session med andra. Så du använder sessionspoolningsläge för dem för att undvika fel vid anslutning när alla "platser" redan är tagna.
  • Använd den inte istället för HAProxy eller någon annan lastbalanserare. Trots att pgbouncer har flera konfigurerbara funktioner som adresserar vad en lastbalanserare adresserar, som dns_max_ttl och du kan ställa in en DNS-konfiguration för den, använder de flesta prod-miljöer HAProxy eller någon annan lastbalanserare för HA. Detta beror på att HAProxy är riktigt bra på att balansera belastningen över liveservrar på ett round robin-sätt, bättre än pgbouncer. Även om pgbouncer är bättre för postgres-anslutningspoolning, kan det vara bättre att använda en liten demon som perfekt utför en uppgift, istället för en större som gör två uppgifter, men värre.

  • Konfigurationsändringar kan vara knepiga. Vissa ändringar av pgbouncer.ini kräver omstart (listen_port och sådant), medan andra såsom admin_users kräver omladdning eller SIGHUP. Ändringar i auth_hba_file kräver omladdning, medan ändringar i auth_file inte gör det.

Den extremt korta översikten av inställningarna ovan begränsas av formatet. Jag inbjuder dig att ta en titt på hela listan. Pgbouncer är den typen av programvara med mycket små mängder "tråkiga inställningar" - de har alla en enorm potential och är av fantastiskt intresse.

Ladda ner Whitepaper Today PostgreSQL Management &Automation med ClusterControlLäs om vad du behöver veta för att distribuera, övervaka, hantera och skala PostgreSQLDladda Whitepaper

Och slutligen, att gå från en kort entusiastisk recension till något där du kanske är mindre nöjd - installationen. Processen beskrivs tydligt i detta avsnitt av dokumentationen. Det enda alternativet som beskrivs är att bygga från git-källor. Men alla vet att det finns paket! Provar båda mest populära:

sudo yum install pgbouncer
sudo apt-get install pgbouncer

kan fungera. Men ibland måste man ta ett extra steg. T.ex. när inget pgbouncer-paket är tillgängligt, prova detta.

Eller till och med:

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

Naturligtvis hjälper det inte längre att lägga till pgdg till /etc/yum.repos.d/. Varken --skip-broken eller rpm -Va --nofiles --nodigest. En enkel

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

skulle vara för lätt. Så du måste bygga libevent2 själv, vilket tar dig tillbaka till positionen när du måste kompilera saker själv. Antingen är det pgbouncer eller ett av dess beroenden.

Återigen - att gräva för djupt med installationens särdrag är utom räckhåll. Du bör veta att du har en stor chans att installera det som paket.

Till sist - frågor som "varför postgres inte erbjuder en inbyggd sessionspooler" kommer om och om igen. Det finns till och med väldigt färska förslag och tankar om det. Men hittills är den mest populära metoden här att använda pgbouncer.


  1. Snabbaste sättet att uppdatera 120 miljoner rekord

  2. Varför flera JOINs är dåliga för Query eller inte kommer i vägen för Optimizer

  3. Hur väljer jag alla kolumner från en tabell, plus ytterligare kolumner som ROWNUM?

  4. Kardinalitetsuppskattning för ett predikat på ett COUNT-uttryck