
PgBouncer ile PostgreSQL Bağlantı Havuzu: Kurulum ve Yapılandırma
PgBouncer 1.21+ kurulumu, session/transaction/statement pool modu karşılaştırması, pgbouncer.ini yapılandırması, prepared statement çakışması ve SHOW STATS/POOLS izleme — Buyukweb VDS perspektifinden pratik rehber.
PgBouncer ile PostgreSQL Bağlantı Havuzu: Kurulum, Yapılandırma ve İzleme
Uygulamanız 200 eşzamanlı istek altında "FATAL: remaining connection slots are reserved" hatası veriyor ve PostgreSQL'in max_connections = 100 sınırını çoktan doldurmuşsunuz. Her bağlantı için yaklaşık 5-10 MB bellek tüketiliyor; 200 bağlantı = 1-2 GB sadece bağlantı overhead'i. Uygulama yavaşlamıyor, doğrudan çöküyor.
Bu senaryonun çözümü PgBouncer — PostgreSQL önüne oturan hafif bir bağlantı havuzu yöneticisi. Bu rehberde PgBouncer 1.21+ kurulumunu, üç pool modunu, kritik pgbouncer.ini parametrelerini, transaction mode'da prepared statement çakışmasını ve izleme sorgularını Buyukweb VDS perspektifinden ele alıyoruz.
Buyukweb perspektifi: cPanel paylaşımlı hosting paketlerimizde veritabanı motoru MariaDB 10.6 LTS'dir; PostgreSQL standart olarak gelmez. Eğer PostgreSQL kullanmak istiyorsanız — özellikle Node.js, Django veya Rails gibi PostgreSQL-ağırlıklı bir stack kuruyorsanız — Buyukweb VDS (₺250/ay başlangıç) üzerinde
apt install postgresql-15veyadnf install postgresql15ile kendiniz kurarsınız; PgBouncer da ayrı pakettir.
Tercih etmeyin: Tek bir uygulama ve 50 eşzamanlı kullanıcıdan az trafiğiniz varsa PgBouncer gereksiz karmaşıklık ekler. PostgreSQL'in varsayılan
max_connections = 100değeri bu yük için yeterlidir. PgBouncer ihtiyacı şu durumlarda ortaya çıkar: 200+ eşzamanlı bağlantı, çok sayıda microservice'in aynı PostgreSQL'e bağlandığı mimari veya serverless/Lambda tipi scale-to-zero uygulamalar.
PostgreSQL'in "Too Many Connections" Sorunu
PostgreSQL her bağlantı için ayrı bir backend process başlatır. Bu process, bağlantı boşta bile RAM ve process tablosunda yer tutar.
Bağlantı havuzu olmadan:
100 uygulama worker → 100 PostgreSQL backend process
200 uygulama worker → "FATAL: too many connections" ❌
PgBouncer ile:
200 uygulama worker → PgBouncer → 20 PostgreSQL backend process ✓
Neden max_connections = 500 yapmak çözüm değildir? Her bağlantı için shared memory ve process overhead artar; PostgreSQL için önerilen değer 100-200 arasındadır. 20-50 gerçek backend bağlantısıyla 500 uygulama worker'ına hizmet etmek PgBouncer'ın tam olarak yaptığı şeydir.
PgBouncer Nedir ve Üç Pool Modu
PgBouncer, uygulama bağlantılarını PostgreSQL bağlantılarından ayıran bir proxy katmanıdır. Varsayılan portu 6432'dir; PostgreSQL'in önüne geçer.
Pool Modu Karşılaştırması
| Özellik | Session Pooling | Transaction Pooling | Statement Pooling |
|---|---|---|---|
| Bağlantı ne zaman serbest bırakılır | Uygulama bağlantısı kapanınca | Transaction bitince | Her SQL ifadesi sonrası |
| Performans kazancı | Düşük | Yüksek | Çok yüksek (ama kısıtlı) |
| SET / RESET desteği | Evet | Hayır | Hayır |
| Prepared statement desteği | Evet | Protokol seviyesinde hayır* | Hayır |
| LISTEN / NOTIFY desteği | Evet | Hayır | Hayır |
| Advisory lock desteği | Evet | Hayır | Hayır |
| Kullanım senaryosu | SET kullanan legacy uygulama | Çoğu modern web uygulaması | Nadiren; basit single-statement |
* Transaction mode'da prepared statement protokolü çakışması ayrı başlıkta ele alınmaktadır.
Session pooling bağlantıyı oturum boyunca tutar — bağlantı overhead'ini ortadan kaldırır ama aynı anda açık uygulama bağlantısı kadar PostgreSQL bağlantısı gerekir. Yoğun trafik için yetersiz.
Transaction pooling PostgreSQL bağlantısını yalnızca transaction süresince kullanır, biter bırakır. En çok kullanılan mod budur — 200 uygulama bağlantısı için 20 PostgreSQL bağlantısı yeterli olabilir.
Statement pooling her SQL ifadesini ayrı bir PostgreSQL bağlantısıyla çalıştırır. Multi-statement transaction desteklemediğinden üretimde nadiren kullanılır.
Kurulum: Ubuntu 22.04 / 24.04 (Buyukweb VDS)
Buyukweb VDS'inde Ubuntu kullananlar için:
sudo apt update
sudo apt install pgbouncer -y
# Versiyon doğrula — 1.18+ iyi, 1.21+ SCRAM-SHA-256 tam destek
pgbouncer --version
# PostgreSQL 15 de kurulacaksa (henüz kurulmamışsa)
sudo apt install postgresql-15 -y
Kurulum: AlmaLinux 9 / RHEL 9 (Buyukweb VDS)
# PostgreSQL PGDG deposu
sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm
sudo dnf -qy module disable postgresql
# PostgreSQL 15 + PgBouncer
sudo dnf install -y postgresql15-server pgbouncer
# PostgreSQL ilk kurulum
sudo /usr/pgsql-15/bin/postgresql-15-setup initdb
sudo systemctl enable --now postgresql-15
pgbouncer.ini Yapılandırması
Ana yapılandırma dosyası /etc/pgbouncer/pgbouncer.ini'dir. Ubuntu'da paket yükleme sonrası otomatik oluşur; AlmaLinux'ta /etc/pgbouncer/pgbouncer.ini el ile oluşturulabilir.
[databases]
; Uygulama veritabanı tanımları
; Format: takma_ad = host=GERÇEK_HOST port=5432 dbname=GERÇEK_DB
uygulama_db = host=127.0.0.1 port=5432 dbname=uygulama_prod
analitik_db = host=127.0.0.1 port=5432 dbname=analitik_prod
; Wildcard — tanımsız her DB adını olduğu gibi ilet
; * = host=127.0.0.1 port=5432
[pgbouncer]
; --- Bağlantı ---
listen_addr = 127.0.0.1 ; Sadece yerel erişim (uygulama aynı sunucudaysa)
listen_port = 6432
; --- Kimlik doğrulama ---
auth_type = scram-sha-256 ; PgBouncer 1.21+ önerilen; eski sürümde md5
auth_file = /etc/pgbouncer/userlist.txt
; --- Pool modu ---
pool_mode = transaction ; Çoğu modern uygulama için önerilen
; --- Bağlantı limitleri ---
max_client_conn = 500 ; Uygulamalardan gelecek maksimum bağlantı
default_pool_size = 20 ; Her DB/kullanıcı çifti için PostgreSQL bağlantısı
max_db_connections = 80 ; Tüm DB'ler için toplam PostgreSQL bağlantısı
min_pool_size = 5 ; Boşta tutulacak minimum bağlantı
reserve_pool_size = 5 ; Yoğun anlık ek kapasite
; --- Zaman aşımı (saniye) ---
server_idle_timeout = 600 ; Boşta PostgreSQL bağlantısını kapat
client_idle_timeout = 0 ; Uygulama zaman aşımı (0 = devre dışı)
server_connect_timeout = 15 ; PostgreSQL'e bağlanma zaman aşımı
reserve_pool_timeout = 5 ; Normal pool dolduğunda reserve_pool_size devreye giriş süresi
; --- Transaction mode ek ayarları ---
server_reset_query = ; Transaction mode'da boş bırakın (session mode için: DISCARD ALL)
ignore_startup_parameters = extra_float_digits,options ; Bazı istemci kütüphaneleri gönderir
; --- Sunucu durumu kontrolü ---
server_check_delay = 30
server_check_query = select 1
; --- Admin / izleme ---
admin_users = pgbouncer_admin
stats_users = pgbouncer_stats
; --- Log ---
log_connections = 1
log_disconnections = 1
log_pooler_errors = 1
stats_period = 60
; --- Sistem dosyaları ---
pidfile = /var/run/pgbouncer/pgbouncer.pid
logfile = /var/log/pgbouncer/pgbouncer.log
Önemli Parametre Özeti
| Parametre | Örnek Değer | Açıklama |
|---|---|---|
max_client_conn |
500 | Uygulama katmanından maksimum bağlantı |
default_pool_size |
20 | DB/kullanıcı başına PostgreSQL bağlantısı |
max_db_connections |
80 | Tüm pool'ların toplam PG bağlantısı (max_connections - 10 yapın) |
min_pool_size |
5 | Boşta tutulacak minimum backend |
reserve_pool_size |
5 | Aşım anında acil kapasite |
reserve_pool_timeout |
5 | Acil kapasiteye geçiş süresi (sn) |
server_idle_timeout |
600 | Boşta backend'i kapat (sn) |
pool_mode |
transaction | session / transaction / statement |
auth_type |
scram-sha-256 | md5 (eski) veya scram-sha-256 (PgBouncer 1.21+) |
userlist.txt ve Kimlik Doğrulama
PgBouncer kullanıcıları PostgreSQL üzerinden doğrulayabilir veya kendi userlist.txt dosyasından okuyabilir. İkinci yöntem daha sık kullanılır.
SCRAM-SHA-256 ile (PgBouncer 1.21+, Önerilen)
# PostgreSQL'de kullanıcı parolasının hash'ini çekme
sudo -u postgres psql -c "SELECT usename, passwd FROM pg_shadow WHERE usename = 'uygulama_user';"
# Çıktıdaki 'SCRAM-SHA-256$...' satırını kopyalayın
; /etc/pgbouncer/userlist.txt — SCRAM-SHA-256 format
"uygulama_user" "SCRAM-SHA-256$4096:...<pg_shadow çıktısı>..."
"pgbouncer_admin" "SCRAM-SHA-256$4096:...<hash>..."
MD5 ile (PgBouncer < 1.21 veya eski kurulumlar)
# MD5 hash: "md5" + md5(parola + kullanici_adi)
echo -n "SİFRE_BURAYAuygulama_user" | md5sum
# Çıktı: abc123def456... → "md5abc123def456..."
; /etc/pgbouncer/userlist.txt — MD5 format
"uygulama_user" "md5abc123def456789012345678901234ab"
"pgbouncer_admin" "md5def456abc789012345678901234abcd"
# Dosya izinleri — sadece postgres kullanıcısı okuyabilmeli
sudo chown postgres:postgres /etc/pgbouncer/userlist.txt
sudo chmod 640 /etc/pgbouncer/userlist.txt
Servis Başlatma ve Yönetim
# Yapılandırma söz dizimi doğrulama (başlatmadan önce)
pgbouncer -d /etc/pgbouncer/pgbouncer.ini --check-config
# Servisi başlat ve otomatik başlatma
sudo systemctl start pgbouncer
sudo systemctl enable pgbouncer
# Durum kontrol
sudo systemctl status pgbouncer
# Yapılandırmayı yeniden yükle (servis durmadan — bağlantıları kesmez)
sudo systemctl reload pgbouncer
# Veya HUP sinyali
kill -HUP $(cat /var/run/pgbouncer/pgbouncer.pid)
Transaction Mode ve Prepared Statement Çakışması
Bu, production'da en sık karşılaşılan sorundur. Transaction pooling modunda her transaction farklı bir backend bağlantısı alabilir. Eğer uygulamanız protokol seviyesinde (binary protocol) prepared statement kullanıyorsa — PREPARE my_stmt AS SELECT...; — ve bağlantı transaction sonrası farklı backend'e verilirse prepared statement bulunamaz, hata alırsınız.
Etkilenen senaryolar:
- psycopg2 / psycopg3
cursor.executeile prepared statement kullanımı - node-postgres (
pg) ileprepareadlı sorgular - JDBC ürünlerinde
prepareStatement+useServerPrepStmts=true
Çözüm 1 — Prepared statement'ı devre dışı bırakın (önerilen):
; pgbouncer.ini — transaction mode'da prepared statement devre dışı
[pgbouncer]
pool_mode = transaction
; Aşağıdaki parametre PgBouncer 1.21+ ile protokol seviyesinde önbelleği kapatır
; (istemci kütüphanesine göre ek ayar gerekebilir — aşağıya bakın)
Çözüm 2 — Uygulama tarafında prepared statement kullanmayı kapatın:
# Python psycopg3 — prepared statement devre dışı
import psycopg
conn = psycopg.connect(
"host=127.0.0.1 port=6432 dbname=uygulama_db user=uygulama_user password=SİFRE",
prepare_threshold=None # Prepared statement kullanma
)
Çözüm 3 — Session pooling'e geçin (prepared statement gerekiyorsa ve transaction mode çalışmıyorsa):
Session pooling ile prepared statement çakışması olmaz; ancak pool verimliliği düşer.
Uygulama Bağlantısı: Doğru Connection String
Uygulama PgBouncer portuna (6432) bağlanır, PostgreSQL portuna (5432) değil.
Python — psycopg2 / psycopg3
import psycopg2
# Transaction mode için CONN_MAX_AGE = 0 (Django) veya kısa yaşam süresi
conn = psycopg2.connect(
host="127.0.0.1",
port=6432, # PgBouncer portu!
dbname="uygulama_db",
user="uygulama_user",
password="SİFRE",
sslmode="prefer"
)
Django settings.py (transaction mode için CONN_MAX_AGE = 0):
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'uygulama_db',
'USER': 'uygulama_user',
'PASSWORD': 'SİFRE',
'HOST': '127.0.0.1',
'PORT': '6432', # PgBouncer
'CONN_MAX_AGE': 0, # Transaction mode: bağlantıyı işlem sonrası bırak
}
}
Node.js — pg kütüphanesi
const { Pool } = require('pg');
const pool = new Pool({
host: '127.0.0.1',
port: 6432, // PgBouncer portu
database: 'uygulama_db',
user: 'uygulama_user',
password: 'SİFRE',
max: 10, // Uygulama tarafı havuz — PgBouncer'a paralel 10 bağlantı
idleTimeoutMillis: 30000,
// Transaction mode + node-postgres: prepared statement kullanmayın
// types kütüphanesi ile pg-types kapatılabilir
});
JDBC (Java / Spring Boot)
jdbc:postgresql://127.0.0.1:6432/uygulama_db?prepareThreshold=0&sslmode=prefer
prepareThreshold=0 server-side prepared statement'ı devre dışı bırakır — transaction pooling ile uyumlu.
İzleme: SHOW STATS, SHOW POOLS
PgBouncer, 6432 portunda pgbouncer adında bir sahte veritabanı sunar. Buraya bağlanarak anlık durum sorgulanır.
# Admin konsoluna bağlan
psql -h 127.0.0.1 -p 6432 -U pgbouncer_admin pgbouncer
-- Genel istatistikler: toplam istek, toplam bekleme, saniyedeki sorgu
SHOW STATS;
-- Pool durumu: aktif/boşta/bekleme bağlantı sayıları
SHOW POOLS;
-- Sunucu bağlantıları (PostgreSQL'e açık)
SHOW SERVERS;
-- İstemci bağlantıları (uygulamadan gelen)
SHOW CLIENTS;
-- Veritabanı başına limit ve anlık durum
SHOW DATABASES;
-- Yapılandırma parametrelerini gör
SHOW CONFIG;
-- Anlık ayar değişikliği (reload etmeden)
SET server_idle_timeout = 300;
-- Yapılandırmayı yeniden yükle (userlist.txt dahil)
RELOAD;
-- Belirli veritabanını geçici durdur / devam ettir
PAUSE uygulama_db;
RESUME uygulama_db;
İzleme Komutu Özeti
| Komut | Ne Gösterir |
|---|---|
SHOW STATS; |
DB başına toplam istek, sorgu süresi, beklemeler |
SHOW POOLS; |
Pool başına cl_active, cl_waiting, sv_active, sv_idle sayıları |
SHOW SERVERS; |
PostgreSQL backend bağlantıları (state, connect_time) |
SHOW CLIENTS; |
Uygulama bağlantıları (state, wait_time) |
SHOW DATABASES; |
DB tanımları, pool_size, max_connections, anlık durum |
SHOW CONFIG; |
Tüm pgbouncer.ini parametreleri ve değerleri |
SHOW POOLS'ta cl_waiting sürekli artıyorsa pool dolu — default_pool_size artırın. sv_idle çok yüksekse min_pool_size düşürülebilir.
Prometheus ile İzleme
pgbouncer_exporter PgBouncer istatistiklerini Prometheus formatına çevirir; 9127 portunda metrikleri sunar. Prometheus + Grafana kuruluysa pgbouncer_* metrikleriyle pool boyutu ve bekleme süresi görselleştirilebilir.
HAProxy + Patroni ile Yüksek Erişilebilirlik (Kısa Bakış)
PgBouncer tek başına yük dengeleme yapmaz. Patroni ile primary/replica cluster kurduysanız PgBouncer önüne HAProxy koyun:
Uygulama → PgBouncer (6432) → HAProxy (5000) → Patroni primary (:5432)
HAProxy, Patroni REST API (/primary, /replica) üzerinden sağlık kontrolü yapar; failover anında PgBouncer yeni primary'ye yönlendirilir. Bu kurulum Buyukweb VDS üzerinde çalışır; birden fazla VDS ve ek yönetim karmaşıklığı gerektirir — tek node için gerekli değildir.
Sıkça Sorulan Sorular
Hangi pool modunu seçmeliyim — session mi, transaction mı?
Çoğu modern web framework'ü (Django, Rails, Node.js Express, FastAPI) transaction modunu destekler. SET komutları, advisory lock veya LISTEN/NOTIFY kullanmıyorsanız transaction pooling seçin — en yüksek bağlantı verimliliğini sağlar. Legacy bir uygulama veya SET bağımlı kütüphane varsa session pooling tercih edin.
Transaction mode'da ORM hazır mı?
SQLAlchemy (pool_pre_ping=True, autocommit=False) ve Django (CONN_MAX_AGE=0) transaction mode ile uyumlu çalışır. ActiveRecord (Rails) de uyumludur. JDBC için prepareThreshold=0 eklemeniz yeterlidir.
PgBouncer kendisi bir SPOF (single point of failure) değil mi?
Evet — tek PgBouncer instance'ı varsa çökünce uygulama PostgreSQL'e ulaşamaz. Çözüm: aynı sunucuda iki PgBouncer instance (farklı port) + systemd servis izleme, ya da birden fazla VDS'de HAProxy + PgBouncer. Küçük ölçekli kurulumlar için systemd ile Restart=always yeterli.
max_client_conn ile default_pool_size arasındaki ilişki nedir?
max_client_conn uygulama katmanından PgBouncer'a gelen maksimum bağlantıdır — bu sayı PostgreSQL bağlantısından bağımsız büyük olabilir. default_pool_size ise gerçek PostgreSQL backend bağlantısıdır. Örnek: max_client_conn=500, default_pool_size=20 — 500 uygulama bağlantısı, 20 PostgreSQL bağlantısıyla servis edilir.
PostgreSQL max_connections ile max_db_connections nasıl dengelenir?
PostgreSQL max_connections değeri sunucu genelinde toplam backend limiti. PgBouncer max_db_connections bu sınırın PgBouncer'a ayrılan payı. Formül: max_db_connections = max_connections - süper kullanıcı_bağlantıları - 5. Örnek: PostgreSQL max_connections=100 ise PgBouncer max_db_connections=90 mantıklı.
PgBouncer SSL desteği var mı?
Evet. Hem istemci (uygulama → PgBouncer) hem sunucu (PgBouncer → PostgreSQL) tarafında TLS yapılandırılabilir:
; pgbouncer.ini
client_tls_sslmode = require
client_tls_key_file = /etc/pgbouncer/pgbouncer.key
client_tls_cert_file = /etc/pgbouncer/pgbouncer.crt
server_tls_sslmode = require
PgBouncer ile pgpool-II arasındaki fark nedir?
PgBouncer yalnızca connection pooling yapar — hafif, hızlı, basit. pgpool-II connection pooling yanı sıra load balancing, replication ve query cache özelliklerine sahip; daha ağır ve yapılandırması karmaşık. Yalnızca bağlantı sayısını yönetmek istiyorsanız PgBouncer, load balancing + replication birlikte gerekiyorsa pgpool-II veya HAProxy + PgBouncer kombinasyonu düşünülebilir.
Sonuç
PostgreSQL "too many connections" hatası alan bir uygulamada PgBouncer'ı devreye almak genellikle birkaç saatlik iştir: kurulum, pgbouncer.ini yapılandırması, userlist.txt oluşturma ve uygulama connection string'ini 5432'den 6432'ye taşıma. Transaction mode seçtiyseniz hazır prepared statement kullandığınızı önceden doğrulayın — bu tek tuzak noktasıdır.
Buyukweb VDS (₺250/ay başlangıç) üzerinde PostgreSQL 15 + PgBouncer 1.21 kurulumu tamamen sizin kontrolünüzde. Root yetkisi vardır, pgbouncer.ini dilediğiniz gibi ayarlanır; Veeam altyapısıyla günlük otomatik sunucu yedeklemesi de Buyukweb tarafından yapılmaktadır.
Teknik destek için: 0850 302 60 70 veya iletişim sayfamız.
İlgili Büyükweb Hizmetleri
Veritabanı odaklı uygulamalar için altyapı seçeneklerimiz:
- VDS Sunucu — root yetkili, PostgreSQL + PgBouncer serbestçe kurulabilir
- E5 v4 VDS — NVMe SSD, yüksek IOPS, PostgreSQL yoğun iş yükleri için
- Fiziksel Dedicated — Tam kontrol, büyük ölçekli veritabanı iş yükleri
- cPanel Web Hosting — MariaDB 10.6 LTS, küçük ve orta ölçekli uygulamalar
Sorularınız için 0850 302 60 70 numaralı destek hattımıza veya iletişim sayfamıza yazabilirsiniz.
Veritabanı Yönetimi İlgili Hizmetlerimiz
Bu yazıda anlatılan teknik konuyu profesyonel altyapıyla deneyimleyin
Etiketler:

