Bağlantı Havuzu (Connection Pool) Nedir?
Kısa tanım
Bağlantı havuzu (connection pool), bir uygulamanın veritabanı gibi bir servise açtığı bağlantıları her istekte yeniden kurmak yerine hazır tutup tekrar tekrar kullanmasını sağlayan mekanizmadır. İstek geldiğinde havuzdan boştaki bir bağlantı ödünç alınır, iş bitince havuza iade edilir. Böylece bağlantı kurma maliyeti tekrarlanmaz ve veritabanına aynı anda açılan bağlantı sayısı kontrol altında kalır.
Diğer adları: Connection Pool, Connection Pooling, Veritabanı Bağlantı Havuzu, DB Pool

Bir bağlantı açmak neden pahalıdır?
Uygulama bir veritabanına ilk kez bağlandığında arka planda bir dizi iş yapılır: TCP bağlantısı kurulur, çoğu zaman üzerine TLS el sıkışması eklenir, kullanıcı adı ve parola doğrulanır, oturum ayarları yüklenir. Sunucu tarafında da her bağlantı için kaynak ayrılır; PostgreSQL örneğin her bağlantıya ayrı bir işletim sistemi süreci açar. Sorgunun kendisi birkaç milisaniye sürerken bağlantıyı kurmak bundan uzun sürebilir.
Her HTTP isteğinde bağlantı açıp kapatan bir uygulama bu bedeli sürekli öder. Trafik arttığında sorun yalnızca gecikme olmaktan çıkar: veritabanının kabul edebileceği bağlantı sayısı sınırlıdır ve sınır aşıldığında yeni bağlantılar reddedilir.
Havuz nasıl çalışır?
Havuz, uygulama ayağa kalkarken ya da ihtiyaç doğdukça belirli sayıda bağlantı açar ve bunları canlı tutar. Kod bir sorgu çalıştıracağı zaman havuzdan bir bağlantı ister, işini bitirince geri verir. Havuzun tamamı doluysa istek, bir bağlantı boşalana kadar sırada bekler. Çoğu havuz kütüphanesinde ayarlanan değerler şunlardır:
- Azami boyut: Aynı anda açık tutulabilecek en fazla bağlantı sayısı.
- Bekleme süresi (acquire timeout): Boş bağlantı için en fazla ne kadar beklenecek; süre dolunca istek hata ile sonlanır.
- Boşta kalma süresi: Kullanılmayan bağlantının ne zaman kapatılacağı.
- Azami ömür: Uzun yaşayan bağlantıların ara ara yenilenmesi; ağ cihazlarının sessizce kopardığı bağlantılara karşı önlem.
Node.js'te yaygın kullanılan pg kütüphanesiyle tipik bir kullanım:
import { Pool } from "pg";
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 10, // en fazla 10 bağlantı
idleTimeoutMillis: 30000, // 30 sn boşta kalan kapanır
connectionTimeoutMillis: 5000, // 5 sn içinde bağlantı yoksa hata
});
const client = await pool.connect();
try {
await client.query("BEGIN");
await client.query("UPDATE stok SET adet = adet - 1 WHERE urun_id = $1", [42]);
await client.query("COMMIT");
} catch (err) {
await client.query("ROLLBACK");
throw err;
} finally {
client.release(); // unutulursa bağlantı havuza dönmez
}Havuz boyutu: büyük olan daha iyi değildir
Sık yapılan hata, yavaşlık görüldüğünde havuzu büyütmektir. Veritabanı sunucusunun işlemci çekirdeği ve disk kapasitesi sınırlıdır; aynı anda yüzlerce sorgu çalıştırmak çoğu zaman her birini yavaşlatır. Küçük bir havuz ve kısa bir bekleme kuyruğu, genellikle büyük bir havuzdan daha iyi toplam verim sağlar.
Asıl hesap toplam bağlantı sayısı üzerinden yapılmalıdır: uygulama örneği sayısı × havuz boyutu, veritabanının sınırının altında kalmalı ve yönetim araçlarıyla migration betiklerine pay bırakmalıdır. PostgreSQL'de max_connections varsayılanı genellikle 100'dür. Dört sunucuda çalışan ve her biri 30 bağlantılık havuz kullanan bir uygulama bu sınırı tek başına aşar.
Uygulama içi havuz ve harici pooler
Havuz, uygulamanın kendi sürecinde yaşayabileceği gibi uygulama ile veritabanı arasına konan ayrı bir servis de olabilir. PostgreSQL dünyasında bunun en bilinen örneği PgBouncer'dır ve üç modda çalışır: bağlantıyı istemci kopana kadar ayıran session, yalnızca bir transaction süresince ayıran transaction ve tek tek ifadeler için ayıran statement modu. Transaction modu çok sayıda istemciyi az sayıda gerçek bağlantıya sığdırır, ancak oturum düzeyindeki SET, LISTEN ve advisory lock gibi özellikler bu modda beklendiği gibi çalışmaz.
Harici pooler'a en çok serverless mimarilerde ihtiyaç duyulur. Her fonksiyon örneği kendi küçük havuzunu açtığında, trafik artışında yüzlerce örnek aynı anda veritabanına yüklenebilir. Ortak bir pooler bu dalgayı tek bir sınırlı havuzda toplar.
Belirtilerden sorunu tanımak
- Bağlantı sızıntısı: Hata durumunda
release()çağrılmazsa bağlantılar birer birer kaybolur, sonunda her istek bekleme süresine takılır. Yukarıdakifinallybloğu bunun için vardır. - Uzun süre açık kalan transaction: Bir transaction içinde dış servis çağrısı yapmak, bağlantıyı o servisin yanıt süresi boyunca kilitler.
- “Too many connections” hataları: Toplam bağlantı hesabının yapılmadığını, çoğu zaman da yatay ölçeklemenin havuz ayarlarıyla birlikte düşünülmediğini gösterir.
Havuz kütüphanelerinin çoğu toplam, boştaki ve bekleyen bağlantı sayısını raporlar. Bu üç değeri izlemek, sorunun veritabanında mı yoksa havuz yapılandırmasında mı olduğunu ayırt etmenin en hızlı yoludur.

