Geçen ay yaşanan bir sistem çöküşü, Auto Scaling’in CPU ya da bellek değil, veritabanı bağlantı sayısının asıl sınırlayıcı faktör olduğunu net bir şekilde ortaya koydu. Küçük bir AWS RDS örneğiyle çalışan bir FastAPI uygulaması, beklenmedik bir anda bağlantı havuzunun dolması nedeniyle cevap veremez hale geldi. Bu deneyim, bağlantı yönetiminin ne kadar kritik olduğunu ve RDS Proxy’in bu soruna gerçek çözüm olup olmadığını sorgulamamıza neden oldu.
Bağlantı Havuzunun Gizli Hesabı: Her Süreç Kaç Bağlantıya İzin Veriyor?
Bir Python süreci için oluşturulan varsayılan bağlantı havuzu genellikle 5-10 bağlantıyla sınırlıdır. Ancak arka planda çalışan işçiler ve aynı veritabanını paylaşan diğer hizmetler bu havuzu hızla tüketebilir. Örneğin, bir FastAPI uygulaması şu yapılandırmaya sahip:
from sqlalchemy.ext.asyncio import create_async_engine
engine = create_async_engine(
settings.DATABASE_URL,
connect_args={"ssl": "prefer"},
pool_pre_ping=True,
pool_size=8,
max_overflow=12, # 8 + 12 = 20 bağlantı/süreç
pool_recycle=1800,
)Bu yapılandırma, her Python sürecine 20 bağlantı sağlar. Ancak uygulamada birden fazla katman varsa — örneğin iki adet AWS Fargate görevi ve arka planda çalışan cron işçileri — bağlantı sayısı hızla artar:
- Her görev: 20 bağlantı × 2 görev = 40 bağlantı
- Rolling deployment sırasında: 40 (eski görev) + 40 (yeni görev) = 80 bağlantı
- Başka bir hizmet: 10 bağlantı
- Ad-hoc sorgular (Alembic, psql vb.): 3-5 bağlantı
Toplamda, t3.micro örneğinin yaklaşık 87 bağlantı sınırına ulaşılabilir. Bu sınır, CPU ya da bellek değil, veritabanının izin verdiği maksimum bağlantı sayısına dayanır. Birden fazla görev çalıştırmaya çalışmak, sistemin "QueuePool limit reached" hatasıyla çökmesine yol açar.
Tetikleyici An: Saat Değişiminde Yaşanan Çöküş
2026 yılının Mayıs ayında, sistemde beklenmedik bir bağlantı havuzu doluluk hatası meydana geldi. Saat değişimi sırasında, dört adet cron işçisi aynı anda tetiklendi ve her biri veritabanına yeni bağlantılar açtı. Aynı anda normal API trafiği de bağlantı talebinde bulunduğunda, havuzdaki bağlantılar hızla tükendi.
Sorunun temel nedenleri şunlardı:
- Havuz boyutu yetersizdi: Mevcut yapılandırma (3/5 bağlantı) sadece sekiz bağlantı sağlıyordu ve bu sayı, senkronize çalışan cron işçileriyle birlikte talebi karşılamak için yeterli değildi.
- Cron işçilerinin eş zamanlı çalışması: Saat değişimiyle birlikte tüm işçiler aynı anda tetiklendi. Bu durum, bağımsız çalışması gereken işlerin anında birikmesine neden oldu.
Çözüm olarak, bağlantı havuzu boyutu 8/12’e (her süreç için 20 bağlantıya) yükseltildi. Bu değişiklik, sistemin bağlantı sınırını aşmaması için dikkatle seçildi. Ölçeklendirme sırasında bile bağlantı sayısının 87’nin altında kalmasını sağlamak için bu değerler tercih edildi.
Bağlantı Havuzunu Optimize Etmek: Doğru Adımlar
Bağlantı havuzunun boyutunu ayarlamak, sorunu geçici olarak çözebilir. Ancak kalıcı bir iyileştirme için şu stratejiler uygulanmalıdır:
1. Bağlantı Sağlığını Kontrol Etmek
- `pool_pre_ping=True`: Veritabanı bağlantısının sağlığını kontrol etmek için basit bir
SELECT 1sorgusu gönderir. Bu sayede, RDS örneği yeniden başlatıldığında ya da bağlantı zaman aşımına uğradığında, SQLAlchemy otomatik olarak yeni bir bağlantı açabilir.
- `pool_recycle=1800`: Bağlantıları 30 dakika sonra yenileyerek, uzun süreli oturumların neden olduğu sorunları önler.
2. Test Ortamında Farklı Bir Yaklaşım Benimsemek
Test ortamında bağlantılar arasında paylaşım yapılmaması daha güvenlidir. `NullPool` kullanarak her test için yeni bir bağlantı açılmasını sağlamak, testlerin güvenilirliğini artırır. Bu yöntem, bağlantılar arasındaki bağımlılıkları ortadan kaldırır ve testlerde oluşabilecek hataları en aza indirir.
from sqlalchemy.ext.asyncio import create_async_engine
engine = create_async_engine(
TEST_DATABASE_URL,
poolclass=NullPool # Testlerde bağlantı havuzunu devre dışı bırak
)3. Sistemdeki Tüm Bağlantıları İzlemek
AWS CloudWatch kullanarak bağlantı havuzu doluluğunu izlemek ve kritik eşikleri belirlemek önemlidir. Örneğin, aşağıdaki gibi bir metriği tanımlayabilirsiniz:
new logs.MetricFilter(
this, "DbPoolExhaustedMetricFilter",
{
logGroup: logs.LogGroup,
filterPattern: logs.FilterPattern.literal('"QueuePool limit of size"'),
metricName: "DbPoolExhausted",
metricValue: "1",
}
)Bu metriğe dayalı olarak, bağlantı havuzu doluluğunun %3’ten fazla olması durumunda uyarı gönderilmesi sağlanabilir. Bu sayede, sorunun büyümeden önce tespit edilmesi mümkün olur.
RDS Proxy: Gerçek Çözüm mü Yoksa Geçici Bir Bandaj mı?
RDS Proxy, bağlantı yönetimini iyileştirmek için sunulan bir hizmettir. Ancak küçük bir t3.micro örneğinde, asıl sorun bağlantı sayısının kısıtlı olmasıdır. Proxy’in avantajları şunlardır:
- Bağlantı havuzunu merkezi olarak yönetme: Uygulama katmanından bağımsız olarak bağlantı sayısını kontrol etmek mümkün olur.
- Bağlantı ömrünü uzatma: Uzun süreli oturumlar Proxy üzerinden yönetilebilir.
Ancak Proxy’in de sınırları vardır:
- Proxy’nin kendi bağlantı sınırı bulunmaktadır. Küçük bir RDS örneği Proxy’e rağmen yine de sınırlı bağlantı sayısına takılabilir.
- Proxy ek bir maliyet getirir. Küçük ölçekli uygulamalar için bu maliyet gereksiz olabilir.
Sonuç olarak, RDS Proxy bağlantı yönetimini kolaylaştırsa da, asıl çözüm sistemin bağlantı sınırlarını doğru şekilde yönetmektir. Bağlantı havuzunun boyutunu ayarlamak, sağlık kontrollerini uygulamak ve sistemdeki tüm bağlantıları izlemek, küçük bir RDS örneğinde bile sorunsuz çalışmayı sağlar.
Bugün sisteminizi gözden geçirin. Bağlantı havuzunuzu doğru şekilde yapılandırdığınızdan emin olun — yoksa gelecekte benzer bir çöküşle karşılaşabilirsiniz.
Yapay zeka özeti
AWS t3.micro üzerinde PostgreSQL bağlantı sınırı nedeniyle oluşan sistem çöküşlerini analiz edin. RDS Proxy’in gerçekten bir çözüm olup olmadığını öğrenin ve bağlantı havuzu optimizasyonu için en iyi uygulamaları keşfedin.