pgBouncer — connection pooling dla PostgreSQL
Opublikowano: 10 kwietnia 2026 · Kategoria: Bazy danych / VPS
PostgreSQL jest wyjątkowo zasobożerny jeśli chodzi o połączenia — każde zajmuje osobny proces systemowy z kilkoma megabajtami RAM. Aplikacja webowa obsługująca 500 równoczesnych użytkowników może generować setki połączeń do bazy, co szybko przeciąża nawet mocny serwer. pgBouncer rozwiązuje ten problem utrzymując małą pulę rzeczywistych połączeń do PostgreSQL i multipleksując do nich wszystkich klientów aplikacji. Wynik: 10-krotnie więcej obsługiwanych klientów, mniejsze zużycie RAM, niższe latency pod obciążeniem.
Instalacja pgBouncer
pgBouncer jest dostępny w standardowych repozytoriach Ubuntu/Debian. Działa jako proxy między aplikacją a PostgreSQL — aplikacja łączy się z pgBouncer (port 6432), a pgBouncer utrzymuje połączenia do Postgresa (port 5432).
# Ubuntu / Debian sudo apt update && sudo apt install pgbouncer -y # Sprawdz wersje pgbouncer --version # Konfiguracja w: # /etc/pgbouncer/pgbouncer.ini — glowna konfiguracja # /etc/pgbouncer/userlist.txt — uzytkownik + haslo (MD5 lub SCRAM) sudo systemctl enable pgbouncer sudo systemctl start pgbouncer sudo systemctl status pgbouncer
Konfiguracja — pgbouncer.ini
Główny plik konfiguracyjny /etc/pgbouncer/pgbouncer.ini — kluczowe sekcje to
[databases] (mapowanie baz) i [pgbouncer] (parametry puli):
[databases] ; Format: alias = host=... port=... dbname=... ; Aplikacja laczy sie jako "myapp" → pgBouncer proxy do lokalnego Postgresa myapp = host=127.0.0.1 port=5432 dbname=myapp ; Mozna mapowac wiele baz analytics = host=127.0.0.1 port=5432 dbname=analytics_db ; Wildcard — wszystkie bazy przez pgBouncer ; * = host=127.0.0.1 port=5432 [pgbouncer] ; Adres nasluchu (aplikacja laczy sie tutaj) listen_addr = 127.0.0.1 listen_port = 6432 ; Plik z uzytkownikami i haslem auth_file = /etc/pgbouncer/userlist.txt auth_type = md5 ; TRYB PULI — kluczowy parametr ; session = polaczenie Postgresa trzymane przez cala sesje klienta ; transaction = polaczenie zwracane po COMMIT/ROLLBACK (ZALECANY) ; statement = zwracane po kazdym pojedynczym zapytaniu (zaawansowane) pool_mode = transaction ; Maks. polaczen od klientow (wszystkich razem) max_client_conn = 1000 ; Domyslny rozmiar puli per (baza, uzytkownik) default_pool_size = 20 ; Zapas polaczen przy skoku ruchu reserve_pool_size = 5 reserve_pool_timeout = 3 ; Czas oczekiwania klienta na wolne polaczenie (sekundy) ; Po tym czasie klient dostaje blad client_login_timeout = 60 ; Logi log_connections = 0 log_disconnections = 0 log_pooler_errors = 1 ; Dostep do bazy statystyk pgbouncer (do monitorowania) stats_users = stats, pgbouncer
Konfiguracja userlist.txt i pg_hba.conf
pgBouncer uwierzytelnia klientów samodzielnie (na podstawie userlist.txt), a
następnie łączy się z PostgreSQL jako zdefiniowany użytkownik. Hasła w userlist.txt muszą
być zahashowane MD5 w formacie md5 + MD5(haslo + uzytkownik):
# Generuj hash MD5 dla uzytkownika "appuser" z haslem "tajnehaslo" echo -n "tajnehasloappuser" | md5sum # Wynik: abc123... (32 znaki) # /etc/pgbouncer/userlist.txt — format: "uzytkownik" "md5HASH" "appuser" "md5abc123def456..." "stats" "md5xyz789..." # Alternatywnie: skopiuj hash z PostgreSQL psql -U postgres -c "SELECT usename, passwd FROM pg_shadow WHERE usename='appuser';"
# /etc/postgresql/15/main/pg_hba.conf # Zezwol na polaczenia od pgBouncer (127.0.0.1 lub dedykowany IP) # TYPE DATABASE USER ADDRESS METHOD host myapp appuser 127.0.0.1/32 md5 host all stats 127.0.0.1/32 md5 # Reload PostgreSQL po zmianach sudo systemctl reload postgresql # Restart pgBouncer po zmianach konfiguracji sudo systemctl restart pgbouncer
Tryby pool_mode — szczegółowe porównanie
| pool_mode | Kiedy zwraca połączenie | Gęstość multipleksowania | Ograniczenia | Użycie |
|---|---|---|---|---|
| session | Koniec sesji klienta | Niska (1:1) | Brak (pełna kompatybilność) | Migracja bez zmian w aplikacji |
| transaction | COMMIT / ROLLBACK | Wysoka (50:1) | Brak SET, LISTEN, temp tables | Typowe aplikacje webowe |
| statement | Koniec każdego zapytania | Bardzo wysoka | Brak transakcji multi-statement | Read-only analytics, cache warmup |
Uwaga dla transaction mode: Jeśli Twoja aplikacja używa
SET search_path, SET LOCAL, LISTEN/NOTIFY, prepared
statements z PREPARE lub tymczasowych tabel — potrzebujesz obejść to przez server_reset_query lub przełączyć na session mode.
Połączenie z aplikacji przez pgBouncer
Aplikacja łączy się z pgBouncer dokładnie tak samo jak z PostgreSQL — zmieniasz tylko port z 5432 na 6432:
# PHP (PDO) — tylko zmiana portu z 5432 na 6432
$pdo = new PDO('pgsql:host=127.0.0.1;port=6432;dbname=myapp', 'appuser', 'tajnehaslo');
# Python (psycopg2)
conn = psycopg2.connect(
host='127.0.0.1',
port=6432,
dbname='myapp',
user='appuser',
password='tajnehaslo'
)
# Node.js (pg)
const pool = new Pool({
host: '127.0.0.1',
port: 6432,
database: 'myapp',
user: 'appuser',
password: 'tajnehaslo',
max: 10 // Pool w aplikacji — dodatkowa warstwa
});
# Django settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'HOST': '127.0.0.1',
'PORT': '6432',
'NAME': 'myapp',
'USER': 'appuser',
'PASSWORD': 'tajnehaslo',
}
} Monitoring — SHOW POOLS i SHOW STATS
pgBouncer udostępnia wirtualną bazę pgbouncer na tym samym porcie do monitorowania
stanu puli. Połącz się jako użytkownik stats:
# Polacz sie do konsoli statystyk psql -h 127.0.0.1 -p 6432 -U stats pgbouncer -- Stan pul polaczen SHOW POOLS; -- database | user | cl_active | cl_waiting | sv_active | sv_idle | maxwait -- myapp | appuser | 45 | 0 | 18 | 2 | 0 -- Statystyki ruchu SHOW STATS; -- database | total_xact_count | total_query_count | avg_xact_duration_us -- Aktywni klienci SHOW CLIENTS; -- Polaczenia do PostgreSQL SHOW SERVERS; -- Konfiguracja live SHOW CONFIG; -- Przeladuj konfiguracje bez restartu RELOAD; -- Zatrzymaj przyjmowanie nowych polaczen (graceful) PAUSE myapp; RESUME myapp;
| Metryka | Znaczenie | Alert gdy |
|---|---|---|
cl_active | Klienci aktywnie wykonujący zapytanie | Zbliża się do max_client_conn |
cl_waiting | Klienci czekający na wolne połączenie | Wartość > 0 przez więcej niż kilka sekund |
sv_active | Połączenia do Postgresa z aktywnym zapytaniem | Równa pool_size = brak rezerwy |
sv_idle | Wolne połączenia w puli | Stale 0 = pool za mały |
maxwait | Najdłuższy czas oczekiwania klienta (s) | Wartość > 1s = problem z rozmiarem puli |
Dobieranie rozmiaru puli — reguły kciuka
- default_pool_size — zacznij od liczby rdzeni CPU serwera PostgreSQL (np. 4-rdzeniowy
= pool 4-8). Zwiększaj stopniowo obserwując
cl_waiting. - max_client_conn — ile klientów (aplikacji) może jednocześnie trzymać połączenie
z pgBouncer. Może być 10-100× większe niż
default_pool_size. - PostgreSQL max_connections — musi być > suma pool_size wszystkich baz +
połączenia administracyjne. Formuła:
max_connections = sum(pool_sizes) + 10. - server_idle_timeout — jak długo pgBouncer trzyma nieużywane połączenie do Postgresa (domyślnie 600s). Zmniejsz do 60-120s jeśli baza ma restrykcyjny limit.
- Wiele pul — każda para (baza, użytkownik) ma osobną pulę. Jeśli masz wiele użytkowników bazy, sumuj ich pool_size przy planowaniu max_connections.