← Natrag
Tehnologija

PgBouncer na 6432 vs direct 5432: zašto transaction pooling pobjeđuje

RiNET Engineering· 18. lipnja 2026.· 5 min čitanja· 22 pregleda
PgBouncer na 6432 vs direct 5432: zašto transaction pooling pobjeđuje
🎧 Poslušaj članak

Kad u produkciji imate tridesetak mikroservisa koji istovremeno pokušavaju doći do baze, klasični connection pool na aplikacijskoj strani postaje iluzija kontrole. Svaki servis otvara svoj set konekcija, svaki ima svoj pool, a baza vidi eksploziju. Bez PgBouncera na 6432, PostgreSQL na 5432 brzo pređe u stanje gdje troši više resursa na održavanje konekcija nego na same upite. To nije teorija — to je brojka koju smo mjerili na vlastitoj arhitekturi kad smo prvi put spojili 35 servisa direktno na bazu. Baza je imala 280 aktivnih konekcija, a CPU je bio na 70% idle, jer je većina vremena odlazila na context switching i lock management. Connection storm nije mit, već svakodnevica kad skalirate bez pravog posrednika.

Razlika između PgBouncera na 6432 i direktnog pristupa na 5432 nije samo u broju konekcija. Suština je u tome što PgBouncer u transaction mode-u preuzima upravljanje životnim ciklusom konekcija na način koji PostgreSQL sam ne može. Kad servis otvori konekciju prema PgBounceru, ona se odmah mapira na jednu od unaprijed definiranih konekcija prema bazi. Čim transakcija završi — commit ili rollback — ta konekcija se vraća u pool. Servis ne drži konekciju otvorenom dok čeka na sljedeći upit, što znači da baza vidi samo onoliko konekcija koliko je pool definirao, a ne koliko servisa imate. U našem slučaju, s 35 servisa i poolom od 20 konekcija, baza je vidjela 20 umjesto 280. To nije optimizacija, to je promjena paradigme.

Transaction pooling funkcionira samo ako su servisi svjesni da ne smiju držati stanje u konekciji. To je ključna zamka koju mnogi preskoče. Kad koristite direktnu konekciju na 5432, možete postaviti search_path, privremene tablice, session varijable i očekivati da će ostati dok konekcija traje. S PgBouncerom u transaction mode-u, nakon svake transakcije konekcija se vraća u pool i sljedeći upit može dobiti potpuno drugu fizičku konekciju. Ako ste u prethodnoj transakciji postavili search_path na "my_schema", sljedeći upit će se izvršiti s defaultnim search_pathom, jer je dobio drugu konekciju. To je najčešći razlog zašto ljudi krive PgBouncer za misteriozne greške, dok je zapravo problem u njihovom kodu koji se oslanja na session state.

Konkretan primjer iz naše infrastrukture: imali smo servis koji je u svakoj transakciji postavljao search_path na specifičnu shemu. Direktno na 5432 radilo je besprijekorno. Kad smo prebacili na PgBouncer na 6432, počeli su dolaziti errori "relation does not exist". Trace je pokazao da servis postavi search_path u prvoj transakciji, ali druga transakcija dobije drugu konekciju i puca jer nema postavljen path. Rješenje nije bilo u gašenju PgBouncera, već u prepisivanju upita da eksplicitno koriste schema.table notaciju. Nakon toga, sve je radilo. Ovisnost o session stateu je arhitektonski dug koji transaction pooling nemilosrdno otkriva. To nije bug PgBouncera, to je feature koji vas tjera na bolji dizajn.

Brojke su ovdje najuvjerljivije. Prije PgBouncera, na direktnoj konekciji na 5432, imali smo 280 aktivnih konekcija od 35 servisa, od čega je 180 bilo u idle stateu, čekajući na sljedeći upit. PostgreSQL na 16 GB RAM-a trošio je 2.5 GB samo na shared buffers i connection overhead, a lock contention je redovito izazivao timeoutove na write operacijama. Nakon što smo postavili PgBouncer s transaction modeom i poolom od 25 konekcija, broj aktivnih konekcija na bazi pao je na 25, RAM potrošnja za konekcije pala je na ispod 200 MB, a lock contention je nestao jer je baza imala dovoljno resursa za stvarni rad. Write throughput se povećao za 40% bez ikakve promjene hardvera. To je razlika između gašenja požara i mirnog rada.

Gradimo ovo svaki dan. Ako tvoja institucija troši mjesece na taj problem — razgovaraj s nama.

Session pooling, drugi mod PgBouncera, nije rješenje za ovaj problem. U session mode-u, svaki klijent dobije svoju konekciju koju drži dok je spojen, što znači da idle konekcije i dalje postoje. To je korisno samo ako imate rijetke klijente koji moraju držati stanje, ali u arhitekturi s puno servisa to ne rješava ništa. Transaction pooling je jedini način da se broj konekcija svede na minimum, ali zahtijeva disciplinu. Servisi moraju biti stateless prema bazi, svaka transakcija mora biti samodostatna, a sve što treba trajati između transakcija mora se čuvati u aplikacijskom sloju, ne u bazi. To nije kompromis, već nužnost za skalabilnost.

Problem s PgBouncerom na 6432 nije u samom alatu, već u percepciji da je to samo proxy koji ne mijenja ponašanje. Mijenja ga drastično. Connection pooling nije samo tehnički sloj, već arhitektonska odluka koja utječe na to kako pišete upite, kako dizajnirate transakcije i kako skalirate servise. Ako vaš kod pretpostavlja da će konekcija biti ista kroz više transakcija, PgBouncer će ga slomiti. Ali ako ga prilagodite, dobit ćete bazu koja diše, umjesto baze koja se guši u vlastitim konekcijama. U našem slučaju, migracija je trajala dva tjedna, ali je eliminirala 90% problema s performansama baze.

Jedna od čestih zamki je i korištenje pripremljenih upita (prepared statements) kroz PgBouncer. U transaction mode-u, pripremljeni upit se veže za jednu fizičku konekciju i ne postoji na drugoj. Ako servis pripremi upit u jednoj transakciji, a zatim ga pokuša izvršiti u sljedećoj, PgBouncer će vratiti grešku jer prepared statement ne postoji na toj konekciji. Rješenje je jednostavno: ne koristiti prepared statements kroz PgBouncer u transaction mode-u, već ih prepustiti driveru koji ih interno cacheira po konekciji, ili koristiti session pooling za specifične slučajeve. Ali to je rijetko potrebno. Većina ORM-ova i drivera već radi s PgBouncerom bez problema, samo treba isključiti session-level feature poput LISTEN/NOTIFY koji ne funkcioniraju u transaction mode-u.

U praksi, PgBouncer na 6432 s transaction modeom postaje standard za svaku produkcijsku bazu s više od deset servisa. Direktna konekcija na 5432 ima smisla samo za administrativne alate, migracije ili jednokratne upite gdje je session state potreban. Za sve ostalo, pooling je jedini način da baza ostane responzivna. Brojke ne lažu: s 280 konekcija na 280, s 25 konekcija na 25. Ne trebate veći server, trebate bolji prometni pravac. PgBouncer je taj semafor koji propušta samo onoliko automobila koliko cesta može podnijeti, a ostale drži u redu dok ne dođu na red. I to je, na kraju, jedina stvar koja broji.

Ako mislite da vaša baza može podnijeti stotine konekcija samo zato što PostgreSQL dopušta, izmjerite CPU idle i lock wait time pa se vratite na ovaj članak.

Ako te zanima ovakva arhitektura ili gradiš nešto slično za svoju instituciju — javi se preko rinet.one.

PostgreSQLPgBouncerconnection poolingdatabase performanceRi.NETsovereign AIAI operativni sustavCroatian AItehnologija

Zanima vas ovakva AI tehnologija?

RiNET gradi sovereign AI rjesenja za javni sektor i poduzeca - od civic intelligence do automatizacije nabave.

Kontaktirajte nas →
0 komentara

Komentari