dataiotech Labs
dbaguidedbaguideDBAdataxtoolsdataopsphere
Home/PostgreSQL/Derinlemesine Analizler/connection-lifecycle-capacity-pooling
[Mühendislik]PostgreSQL PostgreSQL 14–18 · PgBouncer 1.21+Advanced
22 dk okuma

PostgreSQL Bağlantı Yönetimi: Bağlantı Yaşam Döngüsü, Kapasite ve Havuzlama

Uygulama İsteğinden Backend Prosesine: Oturum Durumu, max_connections ve İki Katmanlı Havuzlama

Yazar / Standart:Principal Database Reliability Architect & Linux Systems Engineer
Yönetici Özeti (Executive Architecture Brief):

PostgreSQL bağlantı yaşam döngüsü, aktif/idle/idle-in-transaction kaynak maliyeti, max_connections sınırları, uygulama havuzu ve PgBouncer entegrasyonu, prepared statements ve güvenli yapılandırma rehberi.

PostgreSQL Bağlantı Yönetimi: Bağlantı Yaşam Döngüsü, Kapasite ve Havuzlama

PostgreSQL Bağlantı Yönetimi: Bağlantı Yaşam Döngüsü, Kapasite ve Havuzlama

Kategori: PostgreSQL · Derinlemesine Mimari · Bağlantı ve Kaynak Yönetimi Teknik Seviye: İleri Düzey (Advanced / Expert) Okuma Süresi: 20–25 dakika Dokümantasyon Kapsamı: PostgreSQL 14–18 Yayımlanmış Sürümleri · PgBouncer 1.21+ Fiilen Test Edilen Laboratuvar Ortamı: PostgreSQL 17.11 (Alpine Linux) · PgBouncer 1.26.1


1. Giriş: Bağlantı Yönetimi Neden Bir Mimari Karardır?

Veritabanı operasyonlarında en sık karşılaşılan yanılgılardan biri, bağlantı yönetimini yalnızca bir konfigürasyon satırından (max_connections) ibaret görmektir. Uygulama katmanında trafik arttığında veya mikroservis instance sayısı yükseldiğinde bağlantı hatası alan mühendis ekiplerinin ilk refleksi genellikle bu parametreyi 100'den 500'e veya 1000'e yükseltmek olur.

Oysa PostgreSQL, çok iş parçacıklı (multi-threaded) bir motor değil; bağlantı başına ayrık bir işletim sistemi prosesi (process-per-connection) çalıştıran proses tabanlı bir mimariye sahiptir.

Bağlantı sayısını ölçümsüz olarak artırmak darboğazı ortadan kaldırmaz; yalnızca sorunu veritabanı soket sınırından Linux çekirdeğinin CPU zamanlayıcısına, bellek yöneticisine ve paylaşılan bellek kilitlerine (shared memory lock contention) öteler.

Bu kapsamlı mühendislik rehberinde; bir istemci isteğinin Linux soketinden PostgreSQL backend prosesine uzanan yaşam döngüsünü, aktif/idle/idle-in-transaction durumlarının gerçek kaynak maliyetini, max_connections ve ayrılmış slot sınırlarını, uygulama içi havuz ile PgBouncer'ın iki katmanlı tamamlayıcı rolünü ve izole laboratuvarda ölçülen somut metrikleri inceleyeceğiz.


2. Uygulama İsteğinden Backend Prosesine: Bağlantı Yaşam Döngüsü

Bir istemci uygulamasının (Node.js, Go, Java Spring, Python FastAPI) PostgreSQL'e bir sorgu göndermesi, dört farklı kavramsal katmandan geçer: Bağlantı (Connection), Oturum (Session), İşlem (Transaction) ve Sorgu (Query).

Mimari Akış & Topoloji Şeması (Mermaid)
Mermaid şeması çiziliyor...

▸2.1 Bağlantı, Oturum, Transaction ve Sorgu Ayrımı

KavramYaşam AlanıBaşlangıç ve BitişKaynak Tüketimi
Bağlantı (Connection / Socket)İşletim Sistemi / Ağ KatmanıTCP el sıkışması (3-way handshake) ve TLS anlaşması ile kurulur; TCP FIN/RST ile kapanır.Dosya tanımlayıcısı (file descriptor), kernel TCP soket tamponları (tcp_rmem, tcp_wmem).
Oturum (Session)PostgreSQL ÇekirdeğiKimlik doğrulama başarıyla tamamlandığında başlar; istemci bağlantıyı kesene kadar sürer.Ayrılmış backend Linux prosesi, private virtual memory (relcache, catcache), oturum GUC değişkenleri (search_path, timezone), temp tablolar.
İşlem (Transaction)MVCC / Depolama KatmanıBEGIN ile başlar; COMMIT / ROLLBACK ile biter. Snapshot ilk sorgu ifadesinde (veya SET TRANSACTION SNAPSHOT) alınır. Gerçek 32-bit XID yalnızca ilk veri değiştirme (INSERT/UPDATE/DELETE) veya açık yazma kilidinde tahsis edilir; salt okunur işlemler sanal XID (VirtualTransactionId) kullanır.Tablo ve satır kilitleri (pg_locks), WAL tamponları, aktif transaction slotu, snapshot kaynakları.
Sorgu (Query / Statement)Yürütme Motoru (Executor)SQL metninin backend'e ulaşmasıyla başlar; sonuç satırlarının istemciye iletilmesiyle biter.CPU çekirdekleri, work_mem (sort/hash işlemlerinde), buffer cache erişimi, disk I/O.

▸2.2 Process-per-Connection Mimarisi ve fork() Maliyeti

PostgreSQL'in ana dinleyici prosesi olan Postmaster, 5432 numaralı TCP portunu dinler. Yeni bir istemci bağlandığında Postmaster Linux çekirdeğine fork() sistem çağrısı göndererek bu bağlantıya özel yeni bir backend prosesi oluşturur:

  1. 1Ağ ve El Sıkışma Gecikmesi: TCP 3-way handshake + TLS 1.3 anlaşması tipik olarak 5–15 ms ağ gecikmesi üretir.
  2. 2Linux fork() ve Sayfa Tablosu Kopyalama: Linux fork() çağrısında her ne kadar Copy-on-Write (CoW) kullanılsa da, büyük sanal bellek alanına sahip proseslerde sayfa tablolarının klonlanması CPU maliyeti doğurur.
  3. 3Katalog Önbelleği Isınması: Yeni oluşturulan backend, sistem kataloglarını okuyarak kendi özel relcache ve catcache alanlarını doldurur.
NOT
Bu yüksek kurulum maliyeti nedeniyle, hiçbir modern üretim uygulaması doğrudan her sorgu için yeni bir PostgreSQL bağlantısı açıp kapatmamalıdır (short-lived connections). Bağlantı havuzlayıcıların birincil varlık sebebi bu kurulum maliyetini amortize etmektir.

3. Oturum Durumları ve Gerçek Kaynak Maliyetleri

PostgreSQL'de çalışan tüm backend prosesleri pg_stat_activity görünümünde belirli bir durumda (state) izlenir. Bu durumların anlaşılması, sistemin neden tıkandığını teşhis etmenin temelidir.

▸3.1 Dört Kritik Oturum Durumu

  1. 1`active`: Backend şu anda aktif olarak bir istemci isteğini yürütmektedir. CPU çekirdeğini kullanıyor, disk I/O yapıyor veya kilit/ağ yanıtı bekliyor olabilir.
  2. 2`idle`: Backend soketi açıktır, oturum aktiftir ancak istemci o anda herhangi bir sorgu yürütmemektedir. İstemcinin bir sonraki isteği göndermesini bekler.
  3. 3`idle in transaction`: İstemci BEGIN komutunu vermiş, belki birkaç sorgu çalıştırmış, ancak henüz COMMIT veya ROLLBACK çağırmamıştır. Veritabanı motoru açısından en riskli durumdur!
  4. 4`idle in transaction (aborted)`: İşlem içinde bir sorgu hata vermiş, ancak istemci henüz ROLLBACK çağırmamıştır. İşlem temizlenene kadar bu slot bloklu kalır.
sql
-- Mevcut oturumların durum dağılımını izleme SELECT state, count(*) AS session_count, round(100.0 * count(*) / sum(count(*)) OVER (), 1) AS ratio_pct FROM pg_stat_activity WHERE backend_type = 'client backend' GROUP BY state ORDER BY session_count DESC;

▸3.2 "Idle in Transaction" Neden Bir Numaralı Kararlılık Düşmanıdır?

Uygulama kodu bir HTTP isteği içinde transaction başlatıp, ardından üçüncü parti bir REST API'ye (örneğin ödeme gateway'i veya e-posta servisi) dış çağrı yaptığında; dış servis yanıt verene kadar veritabanı bağlantısı idle in transaction durumunda asılı kalır.

Bu durumun veritabanına faturası çok ağırdır:

  • •Snapshot ve MVCC Bloat: Bu oturumun tuttuğu MVCC snapshot'ı, VACUUM mekanizmasının sistem genelinde güncellenmiş veya silinmiş ölü satırları (dead tuples) temizlemesini engeller. Tablolar ve indeksler hızla şişer (bloat).
  • •Kilit Rekabeti: Oturumun açtığı satır veya tablo seviyesindeki kilitler serbest bırakılamaz. Arkadan gelen masum sorgular bu kilitlerin arkasında birikir.
  • •Slot Tüketimi: Tamamen boşta bekleyen bir istemci, max_connections havuzundan değerli bir slotu rehin tutar.
İPUCU
Üretim ortamlarında idle_in_transaction_session_timeout parametresini kesinlikle boş bırakmayın. Tipik bir OLTP servisi için idle_in_transaction_session_timeout = '30s' veya '60s' değeri, unutulmuş veya kilitlenmiş transaction'ların otomatik sonlandırılarak sistemi felç etmesini önler.

▸3.3 Bellek ve CPU Üzerindeki Çekişme (Resource Contention)

Her PostgreSQL backend prosesi işletim sistemi nezdinde bağımsız bir Linux sürecidir ve bellek tüketimi analiz edilirken paylaşılan sayfalar ile özel ayrılmış alanların birbirinden titizlikle ayrılması gerekir:

  1. 1Paylaşımlı Bellek (Shared Memory) ve RSS Yanılgısı:
  • •top, ps gibi temel işletim sistemi araçlarında gözlenen RSS (Resident Set Size) değeri, backend sürecinin adres uzayına eşlenmiş tüm fiziksel RAM sayfalarını kapsar.
  • •Bu sayfaların önemli bir bölümü shared_buffers, paylaşımlı kilit tabloları ve paylaşılan dinamik kütüphanelerdir.
  • •Bu nedenle tüm backend'lerin RSS değerlerini doğrudan toplamak paylaşımlı belleği yüzlerce kez mükerrer saymaya (overcounting) yol açar.
  • •Bir prosesin gerçek fiziksel ayak izini ölçmek için /proc/[pid]/smaps üzerinden USS (Unique Set Size - yalnızca o prosese ait özel RAM) ve PSS (Proportional Set Size - USS artı paylaşılan sayfaların prosesler arası orantılı payı) izlenmelidir.
  • •Boşta duran tipik bir backend prosesinin taban özel bellek ayak izi (USS) genellikle 2–5 MB aralığındadır (geniş tablo katalogları veya oturum önbellekleri biriktikçe 5–10 MB'a ulaşabilir).
NOT
Varsayımsal Kapasite Modeli (Sizing Heuristic): Literatürde sıkça karşılaşılan *"500 bağlantı açılırsa doğrudan $500 imes 10 ext{ MB} = 5 ext{ GB}$ RAM gider"* hesabı, ölçülmüş kesin bir değer değil; katalog önbellekleri, dinamik kütüphaneler ve işletim sistemi proses yükünü hesaba katan varsayımsal bir en kötü durum kapasite tavanı heuristiğidir. Boşta bekleyen bağlantılar fiziksel RAM'de anında 5 GB tüketmez; ancak eşzamanlı aktif çalışma anında ayrılmamış bellek rezervini tüketme potansiyeli taşır.
  1. 1`work_mem` İşlem Düğümü (Operation Node) Bazında Tahsis Edilir:
  • •Yaygın inanışın aksine, work_mem parametresi *bağlantı başına* veya *sorgu başına* tahsis edilen sabit bir bellek tavanı değildir.
  • •work_mem, sorgu yürütme planındaki her bir işlem düğümü (operation node) için bağımsız olarak tahsis edilir. Ayrıca sıralama ve karma (hash) işlemleri farklı bellek tavanlarına tabidir:
  • •Sıralama Düğümleri (`Sort`, `Merge Join`): En fazla work_mem kadar bellek ayırır.
  • •Karma Düğümleri (`Hash Join`, `Hash Aggregate`): hash_mem_multiplier ile ölçeklenir; azami hash_mem_multiplier * work_mem kadar bellek kullanabilir.
  • •`hash_mem_multiplier` Sürüme Bağlı Varsayılanı:
  • •PostgreSQL 13 ve 14: Varsayılan değer 1.0'dır (eski sürümlerin work_mem eşdeğeri taban davranışını korur).
  • •PostgreSQL 15, 16 ve 17+: Varsayılan değer 2.0'a yükseltilmiştir (karma işlemlerine iki kat tavan tanınır).
  • •Hesaplama Örneği (PG 15+ varsayılanı ile): Bir sorgu yürütme planında 3 adet sıralama (Sort) ve 2 adet karma birleştirme (Hash Join) düğümü varsa, azami bellek talebi $3 \times \text{work_mem} + 2 \times (2.0 \times \text{work_mem}) = 7 \times \text{work_mem}$ olur ($5 \times \text{work_mem}$ değil).
  • •Paralel Sorgu ve Lider Proses Katkısı: Sorguda paralel yürütme kullanılıyorsa (max_parallel_workers_per_gather), her bir worker prosesi kendi alt planındaki düğümler için bağımsız work_mem tahsis eder. Dahası, PostgreSQL'de varsayılan olarak parallel_leader_participation = on olduğundan, sorguyu koordine eden ana backend lider süreci de yürütmeye bizzat katılarak kendi plan düğümleri için work_mem ayırabilir. Örneğin 4 paralel worker ve aktif lider proses (toplam 5 yürütücü) 2 sıralama düğümünü işliyorsa, potansiyel tavan $(4 \text{ worker} + 1 \text{ lider}) \times 2 \times \text{work_mem} = 10 \times \text{work_mem}$ seviyesine ulaşabilir.
  • •Kontrolsüz eşzamanlı bellek tahsisleri fiziksel RAM'i tüketerek Linux çekirdeğinin Out-Of-Memory (OOM) Killer mekanizmasını tetikleyebilir.
  • •CPU Tarafında Context Switching ve ProcArrayLock: Çekirdek sayısı (örneğin 16 vCPU) sınırlıyken yüzlerce aktif prosesin zaman dilimi paylaşımı yapması, CPU'nun zamanının büyük bölümünü sorgu yürütmeye değil, işletim sistemi bağlam değişimine (context switching) ve küme genelindeki aktif transaction tablosunu ve snapshot yönetimini senkronize eden ProcArrayLock hafif kilit (LWLock - Lightweight Lock) çekişmesine harcamasına yol açar.

4. Kapasite Sınırları: max_connections, Ayrılmış Slotlar ve Havuz Talebi

PostgreSQL'de izin verilen azami bağlantı sayısı max_connections ile belirlenir. Ancak bu sayının tamamı sıradan uygulama kullanıcılarına tahsis edilmez.

text
+-----------------------------------------------------------------------------------+ | max_connections (Toplam Kapasite) | +----------------------------------------------------+------------------------------+ | Normal Roller İçin Efektif Limit | Ayrılmış Alanlar | | +---------------+--------------+ | Uygulama İstemcileri, Havuzlar, Analitik | pg_use_... | SUPERUSER | | (max_connections - reserved - superuser_reserved)| (PG 16+) | | +----------------------------------------------------+---------------+--------------+

▸4.1 Sürüme Bağlı Ayrılmış Slotlar (Reserved Slots)

  1. 1`superuser_reserved_connections` (Tüm Sürümler, Varsayılan: 3):
  • •superuser yetkisine sahip roller için ayrılmıştır.
  • •Normal bağlantı yuvaları tükendiğinde, DBA'in psql ile bağlanıp sistemi kurtarabilmesini garanti eder.
  1. 1`reserved_connections` (PostgreSQL 16+ ile Geldi, Varsayılan: 0):
  • •PostgreSQL 16 sürümünde eklenen bu parametre, pg_use_reserved_connections rolüne sahip roller için ayrılmış yuvalar tanımlar.
  • •Amaç: İzleme ajanlarının (Prometheus postgres_exporter, Datadog vb.) süper kullanıcı yetkisine ihtiyaç duymadan, bağlantı doygunluğunda dahi telemetri toplamaya devam edebilmesidir.
  • •PostgreSQL 14 ve 15 Sürümlerinde Durum: PostgreSQL 14 ve 15'te reserved_connections parametresi bulunmaz. Önceden tanımlı pg_monitor veya pg_read_all_stats rolleri yalnızca katalog ve istatistik görünümü okuma yetkisi verir; superuser_reserved_connections kotasına erişim ayrıcalığı sağlamaz. En az yetki (least privilege) ilkesini ihlal ederek izleme ajanlarına SUPERUSER tanımlanması güvenlik açısından önerilmez. Bu sürümlerde izleme bağlantıları normal bağlantı bütçesi (max_connections - superuser_reserved_connections) içinde planlanmalı; uygulama havuzlarının tavanı sınırlanarak veya uygulama rollerine CONNECTION LIMIT konularak telemetriye normal bütçede pay ayrılmalıdır.

Normal bir uygulama rolünün (app_user) bağlanabileceği efektif normal rol limiti:

📐 Formül:\text{Effective Limit} = \text{max\_connections} - \text{superuser\_reserved\_connections} - \text{reserved\_connections}

Örneğin; max_connections = 50, superuser_reserved_connections = 3, reserved_connections = 2 olarak ayarlanmış bir sistemde normal roller için tavan tam olarak 45 bağlantıdır. 46. normal bağlantı isteği motor tarafından reddedilir.

NOT
Çekirdek Çarpanı ve Koşullu Parametreler: - Evrensel Kural Değildir: Saf bellek içi (in-memory) ve CPU-yoğun OLTP iş yüklerinde, çekirdek başına 1–2 katından fazla aktif işçi süreci çalıştırıldığında CPU çekirdekleri aşırı context-switching nedeniyle kilitlenir. Disk I/O beklemesi içeren iş yüklerinde daha yüksek oranlar tolere edilebilse de, çekirdek sayısının 5–10 katı tavanı evrensel bir kural değildir; iş yükünün I/O profiline ve gecikme SLO'larına göre test ortamında kıyaslanarak (benchmark) belirlenmelidir. - Koşullu Zaman Aşımları: Üretim ortamlarında kullanılan idle_in_transaction_session_timeout, idle_session_timeout ve tcp_keepalives_idle parametreleri sihirli evrensel sabitler değildir; mikroservis transaction süreleri, uzun süren batch raporlar ve ağ topolojisine göre kalibre edilmesi gereken koşullu operasyonel örneklerdir. (PostgreSQL 14 ve 15 sürümlerinde reserved_connections parametresi bulunmaz; izleme bağlantıları normal bağlantı bütçesi içinde planlanmalı ve uygulama rollerinin CONNECTION LIMIT ile sınırlandırılmasıyla korunmalıdır).
UYARI
### Canlı Sistemde Bağlantı Tükenmesi Alarmı mı Alıyorsunuz? Şu anda sisteminizde FATAL: sorry, too many clients already veya remaining connection slots are reserved for roles with the SUPERUSER or REPLICATION attribute hatası alıyorsanız, salt okunur teşhis ve güvenli acil müdahale adımları için PostgreSQL Bağlantı Tükenmesi ve too many clients Teşhisi Hata Rehberi'ne geçin.

5. İki Katmanlı Havuzlama Modeli: Uygulama Havuzu ve PgBouncer

Bağlantı yönetiminde yüksek ölçeklenebilirlik, uygulama içi havuzlar ile sunucu önü havuzlayıcıların birbirini tamamladığı iki katmanlı havuzlama (two-tier pooling) mimarisi ile sağlanır.

Mimari Akış & Topoloji Şeması (Mermaid)
Mermaid şeması çiziliyor...

▸5.1 İki Katmanın Rolleri ve Görev Bölümü

Özellik1. Katman: Uygulama Havuzu2. Katman: Sunucu Önü Havuzlayıcı (PgBouncer)
Örnek TeknolojilerHikariCP (Java), pg-pool (Node.js), asyncpg (Python), sqlx (Rust/Go)PgBouncer, pgcat, Odyssey
Çalıştığı YerUygulama prosesi / container içiAyrı bir servis / container / veritabanı VM'i
Çözdüğü Temel SorunUygulama thread'leri için açık bağlantıları yeniden kullanarak her istekte yeni TCP/TLS el sıkışma ve kimlik doğrulama gecikmesini ortadan kaldırmak (Ağ katmanı ve şifreleme devam eder, ancak el sıkışma amortize edilir).Binlerce istemci soketini az sayıda PostgreSQL prosesine çoğullamak (multiplexing).
Ölçeklenme SorunuPod sayısı arttıkça (örneğin 100 pod $\times$ 15 havuz), veritabanına 1.500 soket açar.1.500 istemci soketini arkada 25–40 gerçek PostgreSQL backend'ine indirir.

▸5.2 PgBouncer Havuzlama Modları: Session vs Transaction

PgBouncer üç farklı modda çalışabilir:

  1. 1Session Modu: İstemci bağlandığında ona bir PostgreSQL backend'i tahsis edilir ve istemci soketi kapatana kadar o backend rehin kalır. Çoğullama sağlamaz; yalnızca kimlik doğrulama ve TCP el sıkışma yükünü azaltır.
  2. 2Transaction Modu (Önerilen Mimari): İstemciye yalnızca bir işlem (BEGIN ... COMMIT) yürüttüğü süre boyunca fiziksel bir PostgreSQL backend'i atanır. İşlem biter bitmez backend havuza döner ve sıradaki başka bir pod'un işlemine tahsis edilir!
  3. 3Statement Modu: Her tekil SQL sorgusundan sonra backend bırakılır. Çoklu komut içeren transaction'ları (BEGIN ... COMMIT) desteklemez; analitik dışında nadiren kullanılır.

▸5.3 Transaction Modunun Mimari Kısıtları ve Resmî Kurallar

Transaction pooling (pool_mode = transaction) kullanırken backend sürecinin her transaction (COMMIT / ROLLBACK) sonrasında havuza iade edilerek başka bir istemciye devredilmesi nedeniyle oturum durumu (session state) sınırları ortaya çıkar:

  1. 1`SET` ve Oturum GUC Parametreleri (`SET LOCAL` Zorunluluğu):
  • •Standart SET komutları backend prosesinde kalıcılaşarak sonraki istemcilere sızabilir.
  • •PgBouncer yalnızca belirli başlangıç parametrelerini (client_encoding, datestyle, timezone, standard_conforming_strings, application_name) izler ve eşitler.
  • •Diğer tüm parametre değişiklikleri mutlaka transaction sınırında otomatik sıfırlanan `SET LOCAL` ile yapılmalıdır.
  1. 1Geçici Tablolar (`TEMP TABLE` Yaşam Döngüsü Sınırları):
  • •`ON COMMIT DROP` (Transaction Modunda Desteklenir): CREATE TEMP TABLE ... ON COMMIT DROP ile oluşturulan geçici tablolar, işlem tamamlandığında (COMMIT veya ROLLBACK) PostgreSQL tarafından otomatik ve tamamen silinir. Tablonun yaşam döngüsü doğrudan transaction sınırına bağlı olduğundan, backend süreci bir sonraki istemciye temiz olarak devredilir ve transaction pooling (pool_mode = transaction) ile tam uyumlu çalışır.
  • •`PRESERVE ROWS` / `DELETE ROWS` (Session Modu Gerektirir): Varsayılan ON COMMIT PRESERVE ROWS veya ON COMMIT DELETE ROWS ile oluşturulan geçici tablolar oturum (session) seviyesinde yaşar. Transaction pooling ortamında backend başka bir istemciye geçtiğinde şema ve isim çakışmalarına yol açar. Oturumlar arası kalıcı geçici tablo gerektiren iş yükleri ayrılmış session-mode havuzlara veya doğrudan bağlantılara yönlendirilmelidir.
  1. 1`LISTEN / NOTIFY` Ayrımı:
  • •LISTEN komutu PostgreSQL çekirdeğinde kalıcı bir asenkron soket dinleyicisi kaydeder; bu nedenle transaction modunda çalışmaz (session moduna ihtiyaç duyar).
  • •Buna karşılık bildirim gönderen NOTIFY komutu işlem içinde başarıyla yürütülür.
  1. 1Prepared Statements ve PgBouncer 1.21+ Desteği:
  • •SQL Düzeyi (`PREPARE stmt AS ...`): Backend oturum belleğine bağlı kaldığından transaction modunda desteklenmez.
  • •Protokol Düzeyi (PgBouncer 1.21+ ile Desteklenir): PostgreSQL genişletilmiş sorgu protokolü (Parse, Bind, Execute) üzerinden gelen prepared statement'lar, PgBouncer 1.21+ sürümünden itibaren max_prepared_statements ayarıyla şeffaf biçimde desteklenir.

6. Doğrulanmış Laboratuvar Kanıtları ve Ölçüm Sonuçları

Bu mimari kurallar, spekülatif varsayımlara değil; izole Docker ortamında PostgreSQL 17.11 ve PgBouncer 1.26.1 ile yürütülen deterministik laboratuvar ölçümlerine dayanmaktadır (Mevcut laboratuvar kanıtları ve ham JSON verileri c:/myprojects/dbaguide/.local/notion-outbox/2026-10-28-EDITORIAL-001/connection-lab-evidence.json dosyasında eksiksiz muhafaza edilmektedir).

  • •Laboratuvar Çalıştırma Kimliği: conn-lab-1793279798238
  • •Fiilen Test Edilen İmajlar ve Sürümler:
  • •PostgreSQL: postgres:17-alpine@sha256:266d3c257594e195b309ae9d1805e54c788f1d7b375f56bf6c367aac6c917e7b (PostgreSQL 17.11 on x86_64-pc-linux-musl)
  • •PgBouncer: edoburu/pgbouncer:latest@sha256:8638aa563607256d3c7440437534195f1066a92b68015d89ae9d6b935b444a6d (PgBouncer 1.26.1)
  • •Doğrulanan Motor Parametreleri: SHOW max_connections = 50, superuser_reserved = 3, reserved = 2 $\to$ Efektif Limit: 45.
  • •Örnekleme Yöntemi ve Süre: İşlem yürütme süresi boyunca backend sayıları 50 ms aralıkla anlık olarak örneklenmiş (peakActiveBackends), yük bitiminde anlık snapshot alınmıştır. Test çalışmaları 1–2 saniyelik kısa patlama (short burst) iş yükleridir.
  • •İş Yükü ve İstemci Hacimleri: Senaryolar mimarilerin farklı sınırlarını (doğrudan doygunluk ve ret, havuz içi kuyruklama, proxy çoğullaması ve rolling drain) test etmek üzere farklı istemci talepleriyle (60, 60, 120, 80 istek) koşturulmuştur.
  • •Sınırlar ve Kapsam: Bu laboratuvar çalışması mutlak bir performans üstünlüğü veya tüm mimari özelliklerin genel doğrulamasını iddia etmez; kontrollü bir test ortamında bağlantı sıraya alma, tavan aşımı ret davranışı ve zarif havuz tahliyesini (graceful drain) kanıtlar.

▸6.1 Dört Senaryonun Ölçüm Sonuçları

Metrik1. Doğrudan Bağlantı (Unpooled)2. Uygulama Havuzu (Pool max=20)3. İki Katmanlı Havuz (App + PgBouncer)4. Rolling Drain (Dual Poolers)
Hedef Port55450 (Doğrudan PG)55450 (Doğrudan PG)55451 (PgBouncer)55451 (PgBouncer)
İstemci Eşzamanlılığı60 unpooled istemci60 worker talebi120 worker talebi80 worker (40 eski + 40 yeni)
Başarılı İşlem446012080
Reddedilen İstek16 (%26.7 ret)0 (%0 ret)0 (%0 ret)0 (%0 ret)
Hata Türü53300 (remaining slots are reserved)Yok (Kuyrukta bekleme)Yok (PgBouncer çoğullama)Yok (Zarif tahliye)
Tepe Backend Sayısı45 (44 app + 1 admin)21 (20 app + 1 admin)16 (15 app + 1 admin)16 (15 app + 1 admin)
Bağlantı Kurma Gecikmesip50: 9ms · p99: 13ms*Ölçülmedi/Ayrıştırılmadı (null)*¹*Ölçülmedi/Ayrıştırılmadı (null)*¹*Ölçülmedi/Ayrıştırılmadı (null)*¹
Havuz Bekleme Süresi*Havuzsuz (null)*²p50: 54ms · p99: 69msp50: 56ms · p99: 163msp50: 87ms · p99: 114ms
Sorgu Yürütme Süresip50: 6ms · p99: 10msp50: 11ms · p99: 29msp50: 70ms · p99: 121msp50: 57ms · p99: 75ms
Toparlanma Süresi0.141 saniye0.125 saniye0.010 saniye0.009 saniye

*Tablo Dipnotları:* ¹ *Ölçülmedi / Ayrıştırılmadı (null):* İstemciler önceden ısıtılmış uygulama havuzundan bağlantı edindiği (checkout) için TCP/TLS el sıkışması amortize edilmiştir ve ayrı bir metrik olarak ayrıştırılmamıştır. Bekleme gecikmesi havuz bekleme süresi (poolWaitMs) olarak ölçülmüştür. ² *Havuzsuz (null):* Doğrudan bağlantı senaryosunda havuz katmanı bulunmadığından havuz bekleme süresi söz konusu değildir.

▸6.2 132/82 Kapasite Modeli: Bütçe Tavanı vs Gözlenen Yuva Ayrımı

Laboratuvar senaryomuzda doğrulanmış multi-pooler kapasite modeli şu şekildedir:

  • •Yapılandırma: 2 PgBouncer instance ($K=2$), her birinde 2 Veritabanı $\times$ 2 Kullanıcı (toplam 4 bağımsız havuz), default_pool_size = 15, max_db_connections = 35, max_user_connections = 30.
  • •Tek Pooler Tavanı: $\min(4 \times 15, 2 \times 30, 2 \times 35) = 60$ backend.
  • •İki Pooler Toplam Tavanı: $2 \times 60 = 120$ backend.
  • •Doğrudan İşler (Migration + İzleme + Admin): 12 backend.
  • •Hesaplanan Kapasite Bütçesi: $120 + 12 = 132$ backend.
UYARI
Önemli Metodoloji Ayrımı: Bu 132 değeri, laboratuvarda fiziksel olarak açılan anlık açık soket sayısı veya kesin bir sistem kilitlenmesi değildir. Tüm PgBouncer havuzlarının aynı anda tepe doygunluğa ulaşması durumunda veritabanından talep edilecek teorik bütçe tavanıdır. max_connections = 50 olan bir PostgreSQL kümesinde bu teorik tavan, 82 slotluk bir planlanan kapasite açığına işaret eder. Bu açığın üretimde çökmeye yol açmaması için max_db_connections ve max_user_connections guardrail parametrelerinin doğru sınırlandırılması zorunludur.

7. Güvenli Başlangıç Yapılandırması ve Açıklamalı SQL Örnekleri

▸7.1 PostgreSQL Sunucu Başlangıç Parametreleri (`postgresql.conf`)

Aşağıdaki şablon, tipik bir 8–16 vCPU OLTP üretim veritabanı için güvenli başlangıç parametrelerini içerir:

ini
# ===================================================================== # PostgreSQL Bağlantı ve Bellek Güvenli Başlangıç Şablonu # ===================================================================== # 1. Bağlantı Kapasitesi max_connections = 100 # Donanım çekirdek ve I/O profiline göre kalibre edilmelidir superuser_reserved_connections = 3 # Acil durum DBA erişimi reserved_connections = 2 # PG 16+: İzleme ve audit için (PG 14/15 desteklemez) # 2. Oturum Güvenliği ve Zaman Aşımı Korumaları idle_in_transaction_session_timeout = 30s # Asılı kalan transaction'ları 30 saniyede öldür statement_timeout = 30s # Kaçak analitik sorguların kilit tutmasını önle tcp_keepalives_idle = 60 # Ölü istemci soketlerini 60 sn sonra algıla tcp_keepalives_interval = 10 # Her 10 saniyede bir probe gönder tcp_keepalives_count = 3 # 3 yanıtsız probe sonrası soketi kapat # 3. Bellek Sınırları shared_buffers = 4GB # RAM'in %25'i (tipik 16 GB sistem için) work_mem = 16MB # İşlem düğümü (sort/hash) başına azami bellek maintenance_work_mem = 512MB # VACUUM ve INDEX oluşturma limiti

▸7.2 PgBouncer Güvenli Başlangıç Şablonu (`pgbouncer.ini`)

ini
[databases] app_db = host=127.0.0.1 port=5432 dbname=app_db pool_size=20 max_db_connections=35 [pgbouncer] listen_addr = 0.0.0.0 listen_port = 6432 auth_type = scram-sha-256 auth_file = /etc/pgbouncer/userlist.txt # Havuzlama Stratejisi pool_mode = transaction # En yüksek çoğullama verimliliği default_pool_size = 15 # (DB, User) başına standart backend tavanı min_pool_size = 5 # Boşta hazır bekleyen minimum sıcak bağlantı reserve_pool_size = 5 # Ani yük dalgalanmasında devreye giren yedek havuz reserve_pool_timeout = 3 # İstek 3 sn kuyrukta beklerse rezerve havuzu aç # PgBouncer 1.21+ Prepared Statement Yönetimi max_prepared_statements = 100 # Protokol seviyesinde prepared statements desteği # İstemci ve Sunucu Zaman Aşımları server_idle_timeout = 600 # Kullanılmayan backend'leri 10 dk sonra kapat client_idle_timeout = 0 # İstemci soketlerini kapatma (uygulama havuzu yönetsin) query_timeout = 120 # 2 dakikadan uzun süren sorguları kes

▸7.3 Canlı Telemetri ve Teşhis Sorguları

sql
-- 1. Detaylı Oturum Durumu ve Bekleme Olayları (Wait Events) SELECT pid, usename, client_addr, state, wait_event_type, wait_event, now() - state_change AS state_age, now() - xact_start AS xact_age, left(query, 60) AS query_sample FROM pg_stat_activity WHERE backend_type = 'client backend' ORDER BY xact_age DESC NULLS LAST LIMIT 10; -- 2. Uzun Süredir Boşta Kalan İşlemleri (idle in transaction) Tespit Etme SELECT pid, usename, now() - state_change AS idle_duration, query FROM pg_stat_activity WHERE state = 'idle in transaction' AND (now() - state_change) > interval '10 seconds';

8. Üretime Hazırlık ve Mimari Değerlendirme Listesi (Checklist)

Kendi PostgreSQL altyapınızın bağlantı kapasitesi ve havuzlama sağlığını aşağıdaki 10 maddelik pratik kontrol listesiyle doğrulayabilirsiniz:

  • max_connections Doğrulaması: Fiziksel donanım/vCPU çekirdek kapasitesi, I/O profili ve eşzamanlı aktif işlem ihtiyacına göre ampirik olarak test edilip doğrulandı mı? (Rastgele artırımlar yerine iş yükü profiline göre boyutlandırılmış bütçe tavanı).
  • Ayrılmış Yuva Bütçesi: DBA acil durum kurtarma erişimi (superuser_reserved_connections) ve telemetri/izleme ajanları için sürüme uygun yuva ayrımı (PG 16+ için reserved_connections, PG 14/15 için normal kota içinde ayrılmış pay) doğrulandı mı?
  • İşlem İçi Boşta Koruması: idle_in_transaction_session_timeout parametresi makul bir sınırla (15s – 60s) sınırlandırıldı mı?
  • Uygulama İçi Havuz Boyutlandırması: Kubernetes Pod'larının azami yatay ölçeklenme (HPA tepe noktası) durumunda açacağı toplam bağlantı sayısı hesaplandı mı?
  • PgBouncer Mod Seçimi: Çoğullama gerektiren yüksek eşzamanlı servisler için pool_mode = transaction tercih edildi mi?
  • Prepared Statements Denetimi: PgBouncer 1.21+ kullanılıyorsa max_prepared_statements parametresi tanımlandı mı; eski sürümlerde ORM'lerin hazırlıklı ifade protokolleri kapatıldı mı?
  • Havuz Çoğalma Koruyucuları: Çok kullanıcılı ve çok veritabanlı ortamlarda max_db_connections ve max_user_connections guardrail'leri devrede mi?
  • Keepalive Ayarları: Ağ kesintilerinde ölü kalan bağlantıların temizlenmesi için tcp_keepalives_* parametreleri agresif seviyelere (60s / 10s / 3) çekildi mi?
  • Sorgu Zaman Aşımı: Uygulama veya oturum seviyesinde kontrolsüz kilitleri engelleyecek bir statement_timeout politikası var mı?
  • Telemetri İzolasyonu: Prometheus veya harici izleme araçları için pg_use_reserved_connections rolü yetkilendirildi mi?

9. İlgili Hata Rehberi ve Triad Tamamlayıcıları

▸İlgili Hata Rehberi

*Kritik anlarda salt okunur pg_stat_activity teşhisi, aktif/boşta/işlem içi oturum ayrımı, PG 16 rezerve yuvaları ve operatör onaylı acil tahliye adımları.*

▸Triad Tamamlayıcıları (dataiotech Ekosistemi)

*HikariCP ile PgBouncer karşılaştırması, iki katmanlı havuzlama modeli, session vs transaction modu seçim matrisi ve araç değerlendirmesi.*

*Matematiksel bağlantı bütçesi formülü, Kubernetes rolling deployment %100 surge çarpanı, exponential backoff ve SRE olay eskalasyon kartı.*


10. Kaynaklar ve Resmî Referanslar

3 SİTELİ TRİAD SERİSİ

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 Diğer Üretim Rehberleri

Aynı veritabanı motoruna ait doğrulanmış diğer içerikler.

Tümünü Gör