eduardweb.
PostgreSQLAvansat#devops#prisma#postgresql#pgbouncer

PgBouncer în producție: de la conexiuni blocate la zero downtime cu Prisma

De Teodor Pascu, 22 iun. 2026 · 17 vizualizări · 2 like-uri

Postat 22 iun. 2026
typescript
// schema.prisma
datasource db {
  provider  = "postgresql"
  // Conexiunea prin PgBouncer (portul 6432, de obicei)
  url       = env("DATABASE_URL_WITH_BOUNCER") 
  // Conexiunea directă la Postgres (portul 5432) folosită doar pentru migrări
  directUrl = env("DIRECT_DATABASE_URL")
}

// .env
// DATABASE_URL_WITH_BOUNCER="postgresql://user:pass@host:6432/db?pgbouncer=true&connection_limit=5"
// DIRECT_DATABASE_URL="postgresql://user:pass@host:5432/db"

Dacă folosești Prisma cu Postgres în producție și ai trecut de câteva sute de utilizatori concurenți, probabil ai văzut deja eroarea aia clasică cu "too many clients already". Postgres e superb, dar deschiderea unei conexiuni noi e extrem de costisitoare, consumând în jur de 10MB de RAM per conexiune. Când ai serverless (Lambdas, Vercel) sau zeci de containere în ECS care pornesc deodată, îți pui baza de date în cap în zece secunde.

Aici intervine PgBouncer ca salvator, dar dacă nu înțelegi diferența dintre modurile de pooling, doar muți problema în altă parte.

Session vs Transaction. Unde apar problemele?

PgBouncer are trei moduri, dar în producție te intersectezi doar cu două: session și transaction.

În Session mode, PgBouncer se comportă ca un proxy chior. Când aplicația ta cere o conexiune, PgBouncer îi alocă una din pool și o lasă blocată acolo până când aplicația se deconectează complet. Dacă ai 100 de instanțe de Node.js care stau degeaba, vei avea 100 de conexiuni blocate în Postgres. E un mod inutil pentru microservicii sau serverless.

În Transaction mode, conexiunea fizică la Postgres este eliberată în pool în secunda în care s-a terminat tranzacția (COMMIT sau ROLLBACK). Am avut un proiect unde am redus conexiunile active pe baza de date de la 450 la doar 18, deservind peste 12.000 de utilizatori activi zilnic fără nicio degradare de performanță.

Dar există un trade-off major: pierzi prepared statements (pe care PgBouncer nu le poate mapa ușor între tranzacții diferite pe aceeași conexiune fizică) și nu poți folosi comenzi de sesiune gen SET timezone sau tabele temporare.

Integrarea cu Prisma și marea capcană a migrărilor

Prisma folosește un query engine scris în Rust care, implicit, se așteaptă la conexiuni persistente și folosește prepared statements la greu pentru optimizare. Dacă îl pui peste PgBouncer în transaction mode fără configurare suplimentară, vei umple logurile de erori.

Ca să funcționeze, trebuie să îi spui explicit lui Prisma că e în spatele unui bouncer adăugând parametrul ?pgbouncer=true în connection string. Acest parametru forțează Prisma să folosească protocolul simplu de query (fără prepared statements).

Dar atenție: prisma migrate deploy și prisma db push vor crăpa instant în transaction mode deoarece migrările au nevoie de lock-uri pe tabele care se întind pe mai multe tranzacții. Soluția este să folosești două conexiuni în schema.prisma: una pentru runtime (prin bouncer) și una directă (pentru migrări).

Cum calculăm pool size-ul ideal?

Nu pune valori din burtă. Dacă pui default_pool_size prea mare în PgBouncer, vei sufoca Postgres-ul.

O formulă empirică testată de mine în producție pentru un server DB cu 4 vCPUs:

  • Pe Postgres, setează max_connections = 100.
  • Pe PgBouncer, setează default_pool_size = 30 (aproximativ de 5-7 ori numărul de nuclee CPU, dar nu mai mult de 80% din max_connections de pe DB, ca să lași loc pentru backup-uri, migrări și debugging manual).
  • Pe clienți (în URL-ul Prisma), setează connection_limit=5.

Cu această configurație, 50 de instanțe de aplicație pot rula în paralel. Chiar dacă teoretic ar cere 250 de conexiuni (50 * 5), PgBouncer le va multiplexa rapid prin cele 30 de conexiuni fizice deschise către Postgres, profitând de faptul că majoritatea timpului o conexiune de aplicație doar așteaptă I/O.

Voi cum gestionați conexiunile când scalați? Ați rămas pe PgBouncer sau ați trecut pe alternative mai noi gen Supabase Supavisor?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.