Uygulama Ölçeklenirken Bağlantı Bütçesini Nasıl Koruruz?
Uygulama instance sayısı artarken PostgreSQL backend bütçesi formülü, rolling deployment surge yönetimi, exponential backoff ve SRE nöbetçi eskalasyon kartı.
▸Kısa Açıklama ve Yönetici Özeti
Uygulama filonuz Kubernetes veya bulut ortamında yatayda ölçeklenirken (HPA - Horizontal Pod Autoscaler), veritabanı kapasitesi sihirli bir şekilde kendiliğinden genişlemez.
Bir mikroservisin pod sayısı 10'dan 50'ye çıktığında, her pod içindeki bağlantı havuzunun (HikariCP, Node pg-pool) açtığı soketler bir araya gelerek PostgreSQL'in max_connections tavanına çarpar. Üstelik rolling deployment anında eski ve yeni pod'ların aynı anda çalışması (deploy surge) bu baskıyı ikiye katlar.
Bu operasyonel runbook şu temel soruyu yanıtlar:
▸1. Üç Farklı Bağlantı Sayısını Birbirinden Ayırma
Bağlantı yönetiminde yapılan en temel kavram karmaşası, istemci soket sayısı ile veritabanı proses sayısını eşitlemektir. Sağlıklı bir mimaride üç farklı katmanın sayıları bağımsız izlenmelidir:
| Katman | Metrik Tanımı | Kaynak Maliyeti | Sağlıklı Değer Aralığı |
|---|---|---|---|
| 1. İstemci Bağlantısı ($C_{\text{client}}$) | Uygulama container'larından PgBouncer'a açılan açık TCP oturumları | Düşük (PgBouncer epoll event-loop kullanır; soket başına ~10-20 KB bellek) | Yüzlerce veya binlerce olabilir (örn. 500–5000) |
| 2. PgBouncer Sunucu Bağlantısı ($S_{ ext{pool}}$) | PgBouncer'ın PostgreSQL'e açık tuttuğu aktif/boşta sunucu bağlantıları | Orta (PostgreSQL tarafında açık soket tutar) | vCPU sayısı ve sorgu I/O profiline göre kalibre edilmiş değer (örn. $2 imes ext{vCPU} + ext{disk}$ başlangıç heuristiği) |
| 3. Gerçek PostgreSQL Backend Süreci ($B_{\text{backend}}$) | PostgreSQL çekirdeğinde her oturum için fork edilen bağımsız Linux prosesi | Yüksek (Proses başına 5–10 MB RAM, work_mem, CPU context-switch) | Donanım çekirdek sayısıyla orantılı: genellikle $\le 100$ |
▸2. İki Farklı Mimaride Kapasite Bütçe Hesabı
Kapasite hesabı tek bir formülle genellenemez; mimarinin doğrudan bağlantı mı yoksa PgBouncer ara katmanı mı kullandığına göre iki ayrı hesaplama yapılmalıdır:
#### Mimari A: Doğrudan PostgreSQL Bağlantısı (Direct Connection) Uygulama pod'larının veritabanına doğrudan bağlandığı senaryoda, gereken toplam kapasite pod sayısı ve havuz tavanlarının doğrudan toplamıdır:
$$\text{Doğrudan Kapasite Üst Sınırı} \ge \sum_{i=1}^{M} \left( N_i \times (1 + \text{Surge}_i) \times P_{\max,i} \right) + J_{\text{workers}} + M_{\text{migration}} + \text{Mon} + \text{Admin}_{\text{reserved}}$$
- $M$: Veritabanına bağlanan mikroservis adedi.
- $N_i$: $i$. servisin normal şartlardaki azami pod (instance) sayısı.
- $\text{Surge}_i$: Kubernetes rolling update sırasında eski ve yeni pod'ların eşzamanlı çalışma katsayısı (
maxSurge: 100%ise $1.0$). - $P_{\max,i}$: $i$. servisin pod başına azami havuz boyutu (örn. HikariCP
maximumPoolSize = 10). - $J_{\text{workers}}$: Asenkron worker'lar (Celery, Temporal) için doğrudan ayrılan bağlantılar.
- $M_{\text{migration}}$: CI/CD göç araçları (Flyway, Liquibase) için dedike bağlantı.
- $\text{Mon}$: Gözlem toplayıcıları (Prometheus
postgres_exporter). - $\text{Admin}_{\text{reserved}}$: Acil durum rezerve slotları (
superuser_reserved_connections+ PG 16reserved_connections).
#### Mimari B: PgBouncer ile Çoğullanmış Mimari (PgBouncer Multiplexed) PgBouncer kullanıldığında istemci pod sayısı binlere çıksa dahi veritabanı backend sayısı pod sayısından bağımsızlaşır. Ancak birden fazla PgBouncer instance'ı, veritabanı/kullanıcı havuzları ve PgBouncer'ı atlayan doğrudan işler hesaba katılmalıdır:
$$\text{Yapılandırılmış Backend Tavanı} = \sum_{k=1}^{K} \left[ \sum_{d=1}^{D} \min\left(\text{max\_db\_connections}_d, \sum_{u=1}^{U} \left( \text{pool\_size}_{(u,d)} + \text{reserve\_pool}_{(u,d)} \right)\right) \right] + M_{\text{direct}} + \text{Mon} + \text{Admin}_{\text{reserved}}$$
- $K$: Aktif PgBouncer instance sayısı (HA proxy kümesi veya sidecar adedi).
- $D$ ve $U$: İlgili instance üzerinden erişilen aktif veritabanı ve kullanıcı rolleri adedi.
- $\text{pool\_size}_{(u,d)}$ ve $\text{reserve\_pool}$: Her $(u, d)$ çifti için tanımlı havuz ve rezerv kapasitesi.
- $M_{\text{direct}}$: DDL kilitleri veya oturum durumu gereksinimi nedeniyle PgBouncer'ı atlayarak doğrudan PostgreSQL'e bağlanan migration veya özel batch işleri.
- Yapılandırılmış Tavan vs. Gözlenen Kullanım: Yapılandırılmış tavan tüm havuzların aynı anda dolduğu en kötü durum sınırıdır. Gözlenen backend kullanımı ise tipik OLTP yüklerinde çok daha düşüktür; boyutlandırma yapılırken hem yapılandırılmış tavan
max_connectionsaltında tutulmalı hem de gözlenen kullanım telemetriyle doğrulanmalıdır.
▸3. Rolling Deployment ve %100 Surge Örtüşmesi (Deployment Surge)
En sık yaşanan üretim kesintilerinden biri, normalde sakin çalışan bir sistemin yeni versiyon yayına alınırken aniden FATAL: sorry, too many clients already vermesidir.
#### Çözüm ve Önlemler:
- 1Ara Katmanda PgBouncer Kullanmak: Uygulama podları doğrudan veritabanına bağlanmak yerine PgBouncer'a bağlanırsa, pod sayısı $10 \to 20$ olsa dahi PgBouncer'ın PostgreSQL'e açtığı backend sayısı sabit kalır (örn. 20 backend). Surge dalgası PostgreSQL'e değil, PgBouncer'ın hafif istemci soket kuyruğuna çarpar.
- 2Kubernetes `maxSurge` ve `maxUnavailable` İnce Ayarı: Eğer PgBouncer kullanılamıyorsa,
maxSurge: 25%vemaxUnavailable: 25%yapılarak aynı anda açılan ek pod sayısı sınırlandırılmalıdır. - 3Graceful Shutdown ve `preStop` Hook: Pod SIGTERM aldığında havuz kütüphanesinin mevcut işlemleri bitirip soketleri temizlemesi için
terminationGracePeriodSeconds: 45tanımlanmalıdır.
▸4. Çoklu Kullanıcı ve Veritabanı Kombinasyonu Çoğalması (`User × DB Multiplier`)
PgBouncer devreye alındığında dahi kapasite kontrolsüz bırakılamaz. PgBouncer bağlantı havuzlarını tek bir global torbada toplamaz; her `(veritabanı, kullanıcı)` çifti için ayrı bir sunucu havuzu tahsis eder.
$$\text{Potansiyel Backend Sayısı} = N_{\text{veritabanı}} \times N_{\text{kullanıcı}} \times \text{default\_pool\_size}$$
Örnek Risk ve Kapasite Modeli (Triad Doğrulaması):
- $K = 2$ PgBouncer instance (Yüksek erişilebilirlik kümesi)
- Her instance üzerinde $D = 2$ veritabanı $ imes U = 2$ kullanıcı rolü (Toplam 4 bağımsız havuz)
default_pool_size = 15,reserve_pool_size = 5max_db_connections = 35,max_user_connections = 30- PgBouncer harici doğrudan işler: 2 migration + 5 monitoring + 5 admin reserved = 12 doğrudan backend
Kapasite Hesabı Adımları:
- 1Tek bir pooler instance'ı: Her biri 15 bağlantılık 4 havuz için ham talep $4 imes 15 = 60$ backend'dir.
- 2Sınır denetimi: 2 kullanıcı rolü için $2 imes 30 = 60$ ve 2 veritabanı için $2 imes 35 = 70$ tavanlarına tam uyar ($min(60, 70, 60) = 60$).
- 3İki instance toplamı: $K imes 60 = 2 imes 60 = 120$ backend.
- 4Doğrudan işler eklendiğinde hesaplanan kapasite bütçesi: $120 + 12 = 132$ backend süreci!
Eğer PostgreSQL sunucunuzda max_connections = 50 ise, tüm havuzların eşzamanlı dolması durumunda ortaya çıkacak planlanan kapasite açığı 82 slot olarak belirlenir. Bu değer tekil bir anda 132 aktif soketin açıldığı veya kaçınılmaz bir sistem kilitlenmesi anlamına gelmez; tüm havuzların tepe doygunluğa ulaşması hâlinde planlanması gereken teorik bütçe tavanıdır.
Dengeli Koruma Tedbiri (`pgbouncer.ini`):
[pgbouncer]
default_pool_size = 4 ; 4 havuz x 4 = 16 backend / instance
min_pool_size = 1
reserve_pool_size = 1
max_db_connections = 10 ; Veritabanı başına tavan
max_user_connections = 10 ; Kullanıcı rolü başına tavan
; 2 instance x 16 = 32 pooler + 10 doğrudan = 42 <= 50 max_connections▸5. İstemci Direnci ve Exponential Backoff Mühendisliği
Veritabanı anlık bir yük dalgasına girdiğinde veya havuz dolduğunda, yüzlerce uygulamanın aynı anda milisaniyelik aralıklarla tekrar bağlanmaya çalışması (Thundering Herd / Retry Storm) sistemi tamamen kilitler.
İstemci tarafında üç kritik dayanıklılık paterni uygulanmalıdır:
#### A. Truncated Exponential Backoff + Full Jitter Formülü Tüm istemcilerin aynı anda yeniden denemesini engellemek için gecikmeye rastgele bir sapma (jitter) eklenmelidir:
$$t_{\text{bekleme}} = \text{random}\left(0, \min(t_{\max}, t_{\text{taban}} \times 2^{\text{deneme}})\right)$$
Örnek Parametreler:
- $t_{\text{taban}} = 100\text{ ms}$
- $t_{\max} = 3000\text{ ms}$
- Azami deneme: 3 kez (3 denemede bağlantı alınamazsa HTTP 503 dönerek hızlıca başarısız olun).
#### B. Connection Acquisition Timeout (Fail-Fast İlkesi) Uygulama havuzundan bağlantı alma süresi sınırsız olmamalıdır:
connectionTimeout = 250ms(Örnek SLA senaryo varsayımı; iş yükü SLO'nuza göre kalibre edilmelidir)- Bir web thread'i bu süre (örneğin senaryo varsayımı 250ms) içinde havuzdan bağlantı alamazsa kuyrukta dakikalarca beklememeli, HTTP 503 Service Unavailable dönerek arkasındaki kuyruğu boşaltmalıdır.
▸6. SRE Alarm Eşikleri ve Nöbetçi Eskalasyon Protokolü
Statik ve tek bir alarm eşiği yerine kademeli 3 seviyeli alarm matrisi işletilmelidir:
| Seviye | Tetikleyici Koşul | Değerlendirme Penceresi | Sorumlu | Nöbetçi Aksiyonu |
|---|---|---|---|---|
| P3 - Warning | $\frac{\text{Aktif Bağlantı}}{\max\_connections} > %70$ | for: 10m | Servis Ekibi (Slack) | Pod artışı veya arka plan job zamanlamasını gözden geçir |
| P2 - Critical | $\frac{\text{Aktif Bağlantı}}{\max\_connections} > %85$ | for: 3m | Nöbetçi SRE / DBA (PagerDuty) | Rezerve slot ile pg_stat_activity bağlan; kilitli işlem veya sızıntı kontrolü yap |
| P1 - Emergency | $\frac{\text{Aktif Bağlantı}}{\max\_connections} > %95$ veya FATAL: too many clients logları | for: 1m | Incident Commander + SRE + DB Lead | Acil tahliye: idle in transaction oturumları sonlandır, batch job'ları durdur |
▸7. Nöbetçi SRE / On-Call Olay Müdahale Kartı (Runbook)
# Olay Müdahale Kartı: PostgreSQL Bağlantı Kapasitesi Tükenmesi
- Şiddet Seviyesi: P1 / P2
- İlk Doğrulama Adımları:
1. Grafana panosundan gerçek backend sayısı (pg_stat_database.numbackends) ile PgBouncer istemci kuyruğunu (maxwait) karşılaştır.
2. Sorun veritabanı backend satürasyonu mu, yoksa PgBouncer kuyruk tıkanması mı?
- Teşhis Komutu (Rezerve Süper Kullanıcı Slotu ile):
psql -h db-primary -U db_admin -d postgres -c "
SELECT count(*), state, wait_event_type
FROM pg_stat_activity
WHERE backend_type = 'client backend'
GROUP BY 2, 3;"
- Acil Müdahale Seçenekleri:
A. Hedefli Operatör Müdahalesi (DİKKAT: Toplu pg_terminate_backend kesinlikle otomatik cron veya ilk refleks olarak çalıştırılmamalıdır. Aktif transaction'ı anında ROLLBACK'e zorlar, veri işlem kaybına ve istemcide agresif yeniden bağlanma fırtınasına yol açar. Yalnızca kilit kuyruğunu tıkayan tekil PID izole edildikten sonra operatör kararıyla çalıştırılmalıdır):
-- 1. Önce engellenen kilit PID'sini ve işlem süresini doğrula:
SELECT pid, usename, client_addr, state, now() - xact_start AS xact_duration, query
FROM pg_stat_activity
WHERE state = 'idle in transaction' AND now() - xact_start > interval '2 minutes'
ORDER BY xact_duration DESC LIMIT 5;
-- 2. Yalnızca doğrulanmış ve sistem kilitlenmesine yol açan tekil hedef PID'yi sonlandır:
SELECT pg_terminate_backend(<dogrulanmis_hedef_pid>);
B. Eğer yeni deploy kaynaklı surge yaşanıyorsa:
kubectl rollout pause deployment/<servis-adi>
C. Eğer arka plan ETL havuzu tıkamışsa:
ALTER ROLE etl_worker CONNECTION LIMIT 2;
- Olay Sonrası Aksiyon:
* Kapasite bütçe formülünü yeni pod sayılarıyla güncelle.
* HPA azami sınırını ve Kubernetes maxSurge parametresini gözden geçir.▸8. Sonraki Adım ve Tamamlayıcı İçerikler (Triad)
- 🔍 Mimari Derin İnceleme ve Kapasite (dbaguide): Bağlantı yaşam döngüsü (
fork()maliyeti), oturum durumları,max_connectionsve ayrılmış slot sınırları ile iki katmanlı havuzlama mekaniği.
👉 PostgreSQL Bağlantı Yönetimi: Bağlantı Yaşam Döngüsü, Kapasite ve Havuzlama *(Acil durum müdahalesi için destekleyici runbook: PostgreSQL Bağlantı Tükenmesi Teşhisi)*
- 🛠️ Araç ve Mimari Seçimi (dataxtools): HikariCP ile PgBouncer birlikte nasıl konumlandırılır, session vs. transaction modlarının sınırları nelerdir?
👉 Uygulama Havuzu ile PgBouncer Hangi İhtiyacı Çözer?
▸Resmî Kaynaklar ve İnceleme Notu
- Son İnceleme Tarihi: 29 Ekim 2026 | dataiotech Labs Kıdemli SRE ve Platform Güvenilirlik Ekibi
Restore Tatbikatı & Kurtarma Deneyiminizi Paylaşın
Altyapınızdaki gerçek tatbikat sonuçlarını, RTO/RPO hedeflerinizi ve karşılaştığınız operasyonel engelleri anonim veya isimli olarak paylaşın. Sektör benchmark'ına katkıda bulunun.
Tamamlayıcı Ekosistem İçerikleri: PostgreSQL Bağlantı Kapasitesi ve Bağlantı Havuzu: Teşhis, Araç Seçimi ve SRE Ölçeklenme Bütçesi
Aynı mühendislik konusunu farklı açılardan (teşhis, araç seçimi, olay yönetimi) ele alan diğer dataiotech yayınları:
PostgreSQL Bağlantı Yönetimi: Bağlantı Yaşam Döngüsü, Kapasite ve Havuzlama
Uygulama isteğinden backend prosesine yaşam döngüsü, aktif/idle maliyetleri, max_connections sınırları, iki katmanlı havuzlama ve güvenli başlangıç parametreleri.
Uygulama Havuzu ile PgBouncer Hangi İhtiyacı Çözer?
Uygulama içi havuz ile PgBouncer birbirinin rakibi değil tamamlayıcısıdır. Mod kısıtları, prepared statements ve oturum durumu yönetimi.
Bu mimariyi üretimde test etmek ister misiniz?
DataOpsphere CI/CD şablonlarını ve Docker Compose ortamlarını kopyalayıp hemen çalıştırabilirsiniz.