Türk Bayrağı
Database

PostgreSQL Connection Pooling Nedir?

PostgreSQL'de Connection Pooling:

Bir web uygulaması geliştirdiğinizde başlangıçta her şey harika gider. Ancak trafik artmaya başladığında veritabanı "Error: too many connections" hatasıyla bir anda yanıt vermeyi kesebilir. İşte bu noktada modern yazılım mimarilerinin en kritik parçalarından biri olan Connection Pooling (Bağlantı Havuzlama) devreye girer.

1. Connection Pooling Nedir?

Bir veritabanı bağlantısı açmak, sanıldığından çok daha maliyetli bir işlemdir. Uygulamanız her sorgu için veritabanına gidip "yeni bir kapı" açılmasını istediğinde, PostgreSQL arka planda ciddi bir CPU ve bellek harcayarak yeni bir süreç (process) başlatır.

Bunu bir restoran senaryosuyla canlandıralım:

  • Pooling Olmadan: Her yeni müşteri geldiğinde restoran sahibi sıfırdan yeni bir masa ve sandalye satın alıp kuruyor. Müşteri yemeğini bitirip gidince de sandalyeyi parçalayıp çöpe atıyor. Bu hem çok yavaş hem de korkunç bir maliyettir.
  • Pooling İle: Restoranda halihazırda kurulmuş, örneğin 20 tane masa hazır bekler. Bir müşteri gelince boş masaya oturur, işi bitince masadan kalkar. Masa orada kalmaya devam eder ve bir sonraki müşteri gelip hemen aynı masaya oturur.

2. Neden Pooling Kullanmalıyız?

PostgreSQL, her yeni bağlantı için işletim sistemi seviyesinde yeni bir "fork" işlemi yapar. Bu durum şu teknik sorunları beraberinde getirir:

  • RAM Tüketimi: Her bir bağlantı, veritabanı sunucusu üzerinde yaklaşık 2 MB ile 10 MB arasında RAM tüketebilir. 500 bağlantının aynı anda açılması, sadece bağlantı yönetimi için GB'larca RAM harcanması demektir.
  • Latans (Gecikme): TCP el sıkışması ve kimlik doğrulama işlemleri zaman alır. Bazen bağlantı kurma süresi, SQL sorgusunun kendi çalışma süresinden daha uzun sürebilir.
  • CPU Yükü: Sürekli "process" oluşturup yok etmek işlemciyi yorar ve veritabanının asıl işi olan veri işleme kapasitesini düşürür.

3. Pooling Türleri: Uygulama mı, Sunucu mu?

Bağlantı havuzlamayı iki farklı katmanda yönetebilirsiniz:

A. Uygulama Seviyesinde (Client-Side): Npgsql (C#), Prisma (JS) veya SQLAlchemy (Python) gibi kütüphaneler kendi içlerinde bir havuz yönetir. Kurulumu kolaydır ancak uygulamanızı birden fazla sunucuda (instance) çalıştırıyorsanız, her sunucunun kendi havuzu olacağı için toplam bağlantı sayısı hızla limitleri aşabilir.

B. Veritabanı Önünde (Server-Side / Proxy): Veritabanı ile uygulama arasına PgBouncer gibi bir araç koyulur. Uygulamanız 5000 tane sanal bağlantı açsa bile, PgBouncer bunları sıraya sokar ve veritabanına sadece önceden belirlenmiş (örneğin 100) gerçek bağlantıyı iletir.

4. PgBouncer Çalışma Modları: Hangisini Seçmeli?

Eğer harici bir havuzlayıcı (PgBouncer gibi) kullanıyorsanız, şu üç moddan birini seçmeniz gerekir:

  • Session Pooling (Oturum): Bir kullanıcı bağlanınca, çıkış yapana kadar o kanal sadece ona aittir. En güvenli ama verimliliği en düşük moddur.
  • Transaction Pooling (İşlem): Bağlantı, sadece bir SQL işlemi (Transaction) süresince kullanıcıya verilir. İşlem biter bitmez kanal boşa çıkar ve sıradaki kullanıcıya geçer. Web uygulamaları için en ideal ve en performanslı mod budur.
  • Statement Pooling (Sorgu): Her bir tekil SQL sorgusu için bağlantı değişir. Çok agresiftir ve çoklu sorgu işlemlerinde (transaction) sorun çıkarabilir.

5. Özet ve Altın Kurallar

Veritabanınızın sağlığını korumak için şu kurallara uymanız önerilir:

  • Her zaman bağlantı limitinizin (örneğin 100) biraz altında kalın (Maximum Pool Size = 80-90 gibi).
  • Uygulama kodunuzda using bloklarını veya close/release komutlarını asla unutmayın; havuzun dolmasına neden olursunuz.
  • Serverless (Vercel, AWS Lambda) bir yapı kullanıyorsanız, mutlaka harici bir havuzlayıcı (PgBouncer) tercih edin.

Doğru yapılandırılmış bir Connection Pooling, uygulamanızın trafiği 10 katına çıksa bile veritabanınızın stabil kalmasını sağlar.

C# ve Npgsql ile Gerçek Dünya Senaryosu: Connection Pooling

Teoriyi bir kenara bırakıp doğrudan koda ve gerçek hayat tecrübelerine odaklanalım. .NET ekosisteminde PostgreSQL ile çalışırken standart kütüphanemiz Npgsql'dir. Bu kütüphane, siz hiçbir şey yapmasanız bile arka planda bir havuz (pool) yönetir. Ancak varsayılan ayarlar, Railway gibi kısıtlı kaynak sunan ortamlarda başınıza iş açabilir.

C# Üzerinde Profesyonel Bağlantı Yönetimi

Aşağıdaki örnek, gerçek bir kurumsal projede bağlantı havuzunu nasıl dizginleyeceğinizi gösterir. Özellikle Maximum Pool Size belirlemek, veritabanınızın nefes almasını sağlar.

var connString = "Host=my_db;Username=admin;Password=123;Database=app;Pooling=true;Minimum Pool Size=2;Maximum Pool Size=50;Connection Idle Lifetime=20;";

Bu bağlantı dizesinde ne yaptık?

  • Minimum Pool Size=2: Uygulama ayağa kalktığında hemen 2 bağlantı açar ve hazır tutar. İlk gelen kullanıcı "bağlantı kurma" gecikmesini yaşamaz.
  • Maximum Pool Size=50: Uygulamanız ne kadar coşarsa coşsun, veritabanına aynı anda 50'den fazla yüklenemez. Bu, diğer servislerin (örneğin admin paneli veya yedekleme sistemleri) dışarıda kalmasını engeller.
  • Connection Idle Lifetime=20: Boşa çıkan bağlantı 20 saniye sonra kapatılır. Böylece boşuna RAM tüketilmez.

Gerçek Dünya Senaryosu 1: Microservice Mimarisi

Düşün ki bir e-ticaret siten var ve 3 farklı servisin (Sipariş, Stok, Kullanıcı) aynı PostgreSQL veritabanına bağlanıyor. Railway limitin 100. Eğer her bir servisin Maximum Pool Size ayarını varsayılan (100) bırakırsan, servislerden biri anlık yük aldığında tüm 100 bağlantıyı kapatır ve diğer iki servis "Database Connection Error" vererek çöker.

Çözüm: Sipariş servisine 40, Stok servisine 30, Kullanıcı servisine 20 limit verirsin. Kalan 10 bağlantıyı ise acil müdahale (Debug) için boş bırakırsın.

Shutterstock

Gerçek Dünya Senaryosu 2: Zombi Bağlantı Sorunu

En büyük hatalardan biri, bağlantıyı açıp (conn.Open()) bir hata oluştuğunda kapatmayı unutmaktır. Bu bağlantılar veritabanında "Zombi" olarak kalır ve havuzu şişirir. C#'ta bunun gerçek dünyadaki tek çözümü using bloğu veya IAsyncDisposable kullanmaktır.

using (var conn = new NpgsqlConnection(connString)) {   await conn.OpenAsync();   // İşlem burada yapılır } // Hata olsa bile kod buraya geldiği an bağlantı güvenle havuza iade edilir.

Özetle Neyi Bilmelisin?

Gerçek hayatta Connection Pooling, veritabanını koruyan bir sigorta kutusudur. Eğer bu sigortayı doğru amperajda (Pool Size) ayarlamazsanız, evdeki (sunucudaki) tüm cihazlar aynı anda çalıştığında sigorta atar ve karanlıkta kalırsınız.

Eğer çok yüksek trafikli (saniyede binlerce istek) bir iş yapıyorsan, C# tarafındaki havuz yetmeyebilir. O zaman veritabanının hemen önüne PgBouncer kurarak "Transaction Mode" geçişi yapman şarttır.