Bağlantı Havuzu — Büyük Havuz Hızlı Havuz Değildir
Önce şunu oku: MVCC ve Kilitler — Eski Satır Sürümleri Nerede Yaşar?
30 saniyede özet
Veritabanına bağlanmak pahalıdır, bu yüzden bağlantılar bir havuzda hazır bekletilir. Havuzu büyütmek sorunu çözmez, kuyruğu veritabanının içine taşır. Zaman aşımlarının çoğu, bağlantıyı gereğinden uzun tutan koddan gelir.
Siparişler zaman aşımına uğramaya başlayınca ekip havuzdaki bağlantı sayısını 10’dan 100’e çıkardı. Bir hafta sonra asıl sebep bulundu: ödeme çağrısı transaction’ın içindeydi.
-
Bayt: Siparişler zaman aşımına uğruyor! Havuzdaki bağlantı sayısını onu yüze çıkardık.
-
Sen: Düzeldi mi?
-
Bayt: Bir hafta boyunca tam anlayamadık. Sonra asıl suçluyu bulduk.
-
Bayt: Dört kasalı bir markette içeri daha çok müşteri almak neyi değiştirir?
Havuz neden var?
Yeni bir veritabanı bağlantısı açmak ucuz değildir: ağ bağlantısı, TLS, kimlik doğrulama ve PostgreSQL’de sunucu tarafında yeni bir süreç. Bu yüzden uygulama açık bağlantıları bir connection poolAçık veritabanı bağlantılarını tutan ve isteklere ödünç veren havuz. Bağlantı açmanın maliyetini bir kez öder; boyutu veritabanının kapasitesine göre seçilir.Sözlükte gör →’da tutar ve istekler onları ödünç alıp iade eder.
Spring Boot’ta varsayılan havuz HikariCP’dir. Varsayılan maximumPoolSize 10, bağlantı bekleme süresi (connectionTimeout) 30 saniyedir.
Kafam karıştı, daha basit anlat
Her istek için yeni bağlantı açmak, her yolculuk için yeni araba almak gibidir. Havuz birkaç arabayı hazır tutar, herkes sırayla kullanır.
Uygulamalar veritabanı bağlantılarını neden her istekte açıp kapatmak yerine bir havuzda tutar?
Kaç bağlantı?
Veritabanı sunucusunun 4 çekirdeği var. Havuzu 10'dan 100'e çıkarmak yük altında sorguları hızlandırır mı? Cevabı göster
Genellikle hayır. Veritabanı aynı anda ancak kaynaklarının izin verdiği kadar işi verimli yapar. Fazla bağlantı, sorguları CPU, kilit ve önbellek için yarıştırır; bekleme havuzdan veritabanının içine taşınır.
Adım adım oku
- Veritabanı sunucusunun dört çekirdeği, dört kasa gibidir: aynı anda gerçekten çalışabilen sorgu sayısı sınırlıdır.
- Havuz büyüyünce içeri daha çok bağlantı girer; ama kasa sayısı aynı kaldığı için kuyruk yalnızca kasaların önüne taşınır.
- Transaction içinde yapılan dış ödeme çağrısı, kasada telefonla konuşan müşteri gibi bağlantıyı hiçbir iş yapmadan tutar.
- Dış çağrı transaction'dan önce ya da sonra yapılınca bağlantı yalnızca gerçekten veritabanı işi varken tutulur.
PostgreSQL wiki’si ve HikariCP belgeleri başlangıç noktası olarak şu formülü verir: bağlantı = (çekirdek × 2) + etkin disk sayısı. Bu bir başlangıçtır; son boyutu yük testinde bekleme ve gecikmeye bakarak ayarla.
Birden çok pod varsa toplam önemlidir: pod sayısı × havuz boyutu, veritabanının bağlantı sınırını (PostgreSQL’de varsayılan max_connections 100) aşmamalı.
Kafam karıştı, daha basit anlat
Daha fazla araba her zaman daha hızlı demek değildir. Yol dar ise arabalar sadece trafikte bekler. Veritabanı da aynı anda ancak belli sayıda işi iyi yapar.
Veritabanı 4 çekirdekli, SSD kullanıyor. Havuz boyutu için makul bir başlangıç noktası hangisi?
Servis 12 pod'a ölçeklendi, her birinde havuz boyutu 20. PostgreSQL'in max_connections ayarı varsayılan değerde (100). Ne olur?
Kendin gör
Büyük havuz, hızlı havuz mu?
Tohum 227362Oynat ya da adımla.
Şu an ne oldu?
Çok büyük (100) havuz
Her istek veritabanına gitmeden önce havuzdan bir bağlantı alıyor. Kim bekleyecek: istek mi, veritabanı mı?
Görevler0/3
Bekleyen istek olmadan veritabanını boğaçık
İpucu
Havuzu büyüt.
Veritabanı boştayken istekleri timeout'a düşüraçık
İpucu
Bağlantıyı veritabanı dışında bir şeyi beklerken tut.
Yavaş dış çağrı senaryosunda dengeyi kuraçık
İpucu
Önce kök neden, sonra boyut.
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- Varsayılanla oynat. Çok büyük havuz: kimse beklemedi, veritabanı boğuldu.
- Havuzu “formülden” yap. Dengeli.
- Durumu “yavaş dış çağrı” yap. Veritabanı boşta, istekler timeout alıyor.
- Havuzu büyüt. Timeout gitti, açık transaction’lar birikti.
- Formüle dön ve “kök nedeni düzelt”i aç. Denge geri geldi.
Simülatörde 'yavaş dış çağrı' senaryosunda havuz büyütülünce timeout'lar gitti ama veritabanında açık transaction'lar birikti. Doğru çözüm ne?
Bağlantıyı kim tutuyor?
Havuzun boyutu kadar önemli olan, her bağlantının ne kadar süre tutulduğudur. İki klasik suçlu var:
- Transaction içinde dış çağrı: HTTP isteği beklenirken bağlantı da, transaction da açık kalır.
- bağlantı sızıntısıHavuzdan alınan bir bağlantının iade edilmemesi. Her sızıntı havuzu bir bağlantı küçültür; sonunda bütün istekler bağlantı beklerken timeout alır.Sözlükte gör →: bir hata yolu bağlantıyı iade etmez; havuz yavaş yavaş boşalır.
HikariCP’de leakDetectionThreshold, belirli bir süreden uzun tutulan bağlantıyı alan kod satırını log’a yazar. hikaricp.connections.pending ve active metrikleri de havuzun ne kadar dolu olduğunu gösterir.
Bir bankanın para transferi servisine bakalım. Para çıkmadan önce bir fraud servisine sorulur; o cevabı beklerken bağlantının nerede olduğu, bütün farkı yaratıyor.
Derinleş · Para transferi: bağlantı yalnızca gerektiği kadar 4 dosya · ~68 satır · ilk okumada atlayabilirsin
Kafam karıştı, daha basit anlat
Arabayı alıp park yerinde bekletme. Transaction içinde başka bir servise gidip cevap beklersen, bağlantı da o süre boyunca boşuna tutulur.
Servis birkaç gün çalıştıktan sonra her istekte 'Connection is not available, request timed out' veriyor. Hatalı satır hangisi?
Her belirtiyi en olası nedenine göre ayır.
Tuzaklar
Timeout’a havuz büyüterek cevap vermek. Kök neden yavaş bir sorgu ya da dış çağrıysa, büyük havuz sorunu veritabanına taşır.
Otomatik ölçeklenen pod’lar. Pod sayısı iki katına çıkınca bağlantı sayısı da iki katına çıkar; veritabanının sınırı değişmez.
PgBouncerPostgreSQL önünde çalışan hafif bir bağlantı havuzu. Çok sayıda istemci bağlantısını az sayıda sunucu bağlantısına paylaştırır.Sözlükte gör → transaction modu. Çok sayıda istemciyi az sayıda bağlantıya böler; ama oturuma bağlı özellikler (SET, advisory lock, bazı sürümlerde prepared statement) beklendiği gibi çalışmayabilir.
Bağlantıyı elle almak. DataSource.getConnection() ile alınan bağlantı try-with-resources ile kapatılmazsa, ilk exception onu sızdırır.
PgBouncer transaction pooling moduna geçildikten sonra bazı özellikler garip davranıyor. Hangisi büyük olasılıkla etkilenir?
Kendini sına
Yeni bir veritabanı bağlantısı açmak ucuzdur.
Siparişlerde 'Connection is not available' hataları var. Ekip havuzu 10'dan 100'e çıkarmayı öneriyor. Önce neye bakarsın?
Aklında kalacak üç şey
- 1 Veritabanı aynı anda ancak işlemci ve diskinin izin verdiği kadar işi verimli yapar. Fazla bağlantı sorguları birbiriyle yarıştırır.
- 2 Havuz boyutu için başlangıç noktası (çekirdek × 2) + disk sayısıdır; son karar ölçerek verilir. Sunucu sayısı × havuz boyutu, veritabanının bağlantı sınırını aşmamalıdır.
- 3 Bağlantı zaman aşımında önce bağlantıyı kimin, neden uzun tuttuğuna bak: transaction içinde yapılan bir dış çağrı ya da geri verilmeyen bir bağlantı.
4 kart sonraki derste seni bekliyor