PostgreSQL Connection Pooling: Architektur, Sizing & PgBouncer im Produktivbetrieb
Erstellt: 2026-11-08 · Zuletzt aktualisiert: 2026-11-08 · Nejat Hakan
Management Summary: PostgreSQL nutzt eine prozessbasierte Concurrency-Architektur (Process-per-Connection): Jeder verbundene Client erzeugt einen eigenständigen Backend-Prozess, der 5–15 MB RAM, private Speicherbereiche und CPU-Scheduler-Slices bindet. Ein schlichtes Hochsetzen von
max_connections = 2000inpostgresql.confführt in Produktionsumgebungen unweigerlich zu drastischem CPU-Cache-Thrashing, explodierenden Abfragelatenzen und OOM-Kills (Out-of-Memory). Dieser Praxisleitfaden demonstriert, wie PgBouncer als performanter Connection-Proxy unter Debian Linux eingerichtet wird, wie Connection-Pools nach der Warteschlangentheorie dimensioniert werden und wie/etc/pgbouncer/pgbouncer.inifür hochperformante Microservice-Architekturen konfiguriert wird.
-
Process-per-Connection Overhead
Den Flaschenhals verstehen: Warum hunderte untätige Backend-Prozesse den Linux-Scheduler überlasten und physischen RAM vergeuden.
-
Vergleich der Pooling-Modi
Session vs. Transaction vs. Statement: Den passenden Modus anhand von ORM-Semantiken und Transaktionsgrenzen fundiert auswählen.
-
Produktionskonfiguration
Härtung von
/etc/pgbouncer/pgbouncer.iniunter Debian: Pool-Sizing-Formeln, SCRAM-Authentifizierung, Timeouts und Systemd-Service. -
Admin-Konsole & Benchmarking
Pool-Gesundheit live über administrative Pseudo-Tabellen (
SHOW POOLS,SHOW CLIENTS) überwachen und Durchsatzgewinne mitpgbenchverifizieren.
1. Das Process-per-Connection-Dilemma & Pool-Sizing
Im Gegensatz zu Thread-basierten Datenbanksystemen (wie MySQL oder MS SQL) forkt PostgreSQL für jeden verbundenen Client einen vollständig autonomen Betriebssystem-Prozess. Wenn hunderte Microservices parallel Verbindungen öffnen:
%%{init: {'flowchart': {'wrappingWidth': 350}}}%%
flowchart TB
CLI["1.000+ App-Verbindungen<br/>(Inaktive Microservices)"]
PGB["PgBouncer Proxy-Dienst<br/>(libevent Event-Loop)"]
PG["PostgreSQL Server-Engine<br/>(Fester Pool: 30 Backends)"]
RAM["Physischer RAM<br/>Geschützt vor OOM"]
CLI -->|"Schnelle Handshakes"| PGB
PGB -->|"Multiplext Queries"| PG
PG -->|"CPU-Cache-Treffer"| RAM
Die Mathematik des Verbindungs-Overheads
- Speicherfraß: 1.000 inaktive Backend-Prozesse belegen jeweils 5–15 MB privaten Arbeitsspeicher (RSS) – das bindet 10–15 GB RAM, ohne eine einzige Abfrage zu berechnen.
- Context-Switching: Wachen hunderte Prozesse gleichzeitig auf, um kurze Queries auszuführen, verbringt der Linux-CPU-Scheduler erhebliche Zyklen mit Kontextwechseln. Die CPU-L1/L2/L3-Caches werden entwertet (Cache Thrashing).
- Die Dimensionierungsformel: Der maximale Durchsatz einer relationalen Datenbank wird erreicht, wenn die Anzahl aktiver Server-Backends exakt auf die Hardwarekapazitäten abgestimmt ist:
Max. aktive Verbindungen ≈ (CPU-Kerne × 2) + Effektive NVMe-Kanäle / Spindeln
Auf einem Bare-Metal-Server mit 16 CPU-Kernen und NVMe-Speicher liefert ein interner PostgreSQL-Pool von 32 bis 40 aktiven Backend-Prozessen den maximalen Transaktionsdurchsatz. PgBouncer bedient davor problemlos 5.000+ Client-Verbindungen bei minimalem Speicheraufwand.
2. Vergleich der PgBouncer-Pooling-Modi
| Merkmal / Verhalten | Session Pooling (session) |
Transaction Pooling (transaction) |
Statement Pooling (statement) |
|---|---|---|---|
| Verbindungs-Lebenszyklus | Wird beim Client-Connect zugewiesen; Freigabe erst beim Disconnect. | Zuweisung bei BEGIN (oder erster Query); Freigabe sofort bei COMMIT/ROLLBACK. |
Zuweisung pro einzelnem SQL-Statement; sofortige Rückgabe. |
| Multiplexing-Effizienz | Gering (Server-Verbindung blockiert während Client-Idle-Zeiten). | Extrem hoch (100 Server-Verbindungen bedienen 10.000 Clients). | Maximal, verhindert aber Multi-Statement-Transaktionen. |
| Prepared Statements | Uneingeschränkt und nativ unterstützt. | In modernem PgBouncer (ab v1.21+) via Protokoll-Tracking unterstützt. | Strikt verboten. |
Session-Variablen (SET) |
Bleiben über die gesamte Client-Session hinweg erhalten. | Werden zwischen Transaktionen verworfen (erfordert SET LOCAL). |
Strikt verboten. |
| Empfohlener Einsatzzweck | Monolithische Legacy-Anwendungen mit Session-Abhängigkeiten. | Moderne Web-APIs, Microservices, ORMs (Prisma, Django, Hibernate). | Reine Key-Value-Lese-Caches ohne Transaktionslogik. |
3. Produktions-Setup von PgBouncer unter Debian
3.1. Paket-Installation
Installieren Sie PgBouncer aus den offiziellen Debian-Repositories:
3.2. Konfiguration: /etc/pgbouncer/pgbouncer.ini
; Datei: /etc/pgbouncer/pgbouncer.ini
[databases]
; Mappt externe Verbindungsanfragen auf die lokale PostgreSQL-Instanz
enterprise_prod = host=127.0.0.1 port=5432 dbname=enterprise_prod auth_user=postgres
* = host=127.0.0.1 port=5432
[pgbouncer]
; Netzwerk-Konfiguration
listen_addr = 0.0.0.0
listen_port = 6432
unix_socket_dir = /var/run/postgresql
; Authentifizierung
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt
auth_query = SELECT usename, passwd FROM pg_shadow WHERE usename=$1
; Dimensionierung des Connection-Pools
pool_mode = transaction
max_client_conn = 5000
default_pool_size = 30
min_pool_size = 10
reserve_pool_size = 5
reserve_pool_timeout = 5.0
max_db_connections = 60
; Timeouts und Verbindungskontrolle
server_idle_timeout = 600
server_connect_timeout = 15
client_idle_timeout = 0
query_timeout = 120
; Logging und Administration
admin_users = postgres, admin
stats_users = monitoring, nagios, prometheus
logfile = /var/log/postgresql/pgbouncer.log
pidfile = /var/run/postgresql/pgbouncer.pid
3.3. Authentifizierungs-Konfiguration: /etc/pgbouncer/userlist.txt
PgBouncer nutzt eine Datei mit Benutzerkonten und SCRAM-Hashes:
; Datei: /etc/pgbouncer/userlist.txt
"postgres" "SCRAM-SHA-256$4096:5a9...=="
"app_runtime_user" "SCRAM-SHA-256$4096:7b2...=="
Berechtigungen absichern und Dienst aktivieren:
sudo chown postgres:postgres /etc/pgbouncer/userlist.txt /etc/pgbouncer/pgbouncer.ini
sudo chmod 600 /etc/pgbouncer/userlist.txt
sudo systemctl enable --now pgbouncer
sudo systemctl status pgbouncer
4. Live-Administration & Stresstests mit pgbench
4.1. Verbindung zur virtuellen Admin-Konsole
PgBouncer stellt eine interne Pseudo-Datenbank namens pgbouncer für Echtzeitdiagnosen bereit:
Wichtige Diagnosebefehle:
-- Zustand der Connection-Pools prüfen
SHOW POOLS;
-- Ausgabe:
-- database | user | cl_active | cl_waiting | sv_active | sv_idle | sv_used | sv_tested | maxwait
-- -----------------+----------+-----------+------------+-----------+---------+---------+-----------+---------
-- enterprise_prod | app_user | 250 | 0 | 28 | 2 | 0 | 0 | 0
-- Aktive Client-Verbindungen inspizieren
SHOW CLIENTS;
-- Aktive Server-Backend-Verbindungen inspizieren
SHOW SERVERS;
-- Aggregierte Durchsatz-Statistiken abrufen
SHOW STATS;
4.2. Benchmarking: Direktverbindung vs. PgBouncer (pgbench)
Stresstest mit 1.000 parallelen Clients:
Direktverbindung (Führt zu Überlastung oder too many connections)
pgbench -h 127.0.0.1 -p 5432 -U app_runtime_user -c 1000 -j 10 -t 50 enterprise_prod
# Ergebnis: ERROR: FATAL: remaining connection slots are reserved for non-replication superuser connections
Verbindung über PgBouncer (Stabiler Durchsatz, minimale Wartelatenz)
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 50
query mode: simple
number of clients: 1000
number of threads: 10
maximum number of tries: 1
number of transactions per client: 50
number of transactions actually processed: 50000/50000
latency average = 14.281 ms
initial connection time = 182.102 ms
tps = 14210.421051 (without initial connection time)
Über PgBouncer werden 1.000 parallele Client-Verbindungen sauber über lediglich 30 Server-Prozesse gemultiplext – ohne Socket-Abbrüche und mit stabiler Minimal-Latenz.