Gökmen Tuksavul

Blog Yazısı

2026-07-26

Spring Boot API Performans Notları

Spring Boot projelerinde API performansını artırmak için SQL optimizasyonu, Hibernate L2 cache, Redis ve bağlantı havuzu ayarları gibi kritik backend tekniklerini öğrenin.

Spring BootAPIPerformance

Sponsorlu

Modern web uygulamalarında performans, sadece kodun hızı değil, aynı zamanda sistem kaynaklarının verimli kullanımıdır. Özellikle yüksek trafikli mikroservis mimarilerinde, yanlış yapılandırılmış bir veritabanı bağlantı havuzu veya optimize edilmemiş sorgular tüm sistemi kilitleyebilir. Bu yazıda, üretim ortamında edindiğim tecrübelerle Spring Boot API performansını nasıl optimize edebileceğinizi adım adım inceleyeceğiz.

1. Veritabanı Bağlantı Yönetimi ve HikariCP

Spring Boot varsayılan olarak HikariCP bağlantı havuzunu kullanır. HikariCP, hızıyla bilinse de varsayılan ayarlar her zaman ideal değildir. maximum-pool-size değerini çok yüksek tutmak CPU üzerinde context switching maliyetini artırırken, çok düşük tutmak isteklerin kuyrukta beklemesine ve timeout hatalarına neden olur.

İpucu: Havuz boyutunu belirlemek için şu formülü baz alabilirsiniz: connections = ((core_count * 2) + effective_spindle_count).

Örnek optimize edilmiş yapılandırma: ``yaml spring.datasource.hikari: maximum-pool-size: 15 minimum-idle: 5 idle-timeout: 300000 connection-timeout: 20000 max-lifetime: 1800000 ``

2. Hibernate N+1 Problemi ve EntityGraph Çözümü

Birçok geliştirici farkında olmadan ilişkili dataları çekerken onlarca gereksiz sorgu atılmasına (N+1 problemi) neden olur. Örneğin, 10 tane 'Post' nesnesini çekerken her birinin 'Author' bilgisini ayrı sorgularla çekmek ciddi bir gecikmeye yol açar.

@OneToMany ilişkilerde FetchType.LAZY kullanmak yetmez; sorgu anında JOIN FETCH veya JPA 2.1 ile gelen @EntityGraph kullanarak bu sorunu çözmelisiniz. Bu yaklaşım, DB tur sayısını 11'den (1 ana sorgu + 10 alt sorgu) 1'e indirebilir.

@EntityGraph(attributePaths = {"authors", "comments"})
List<Post> findAllByPublishedTrue();

3. Redis ile Dağıtık Önbellekleme (Distributed Caching)

Sık değişmeyen ancak hesaplaması veya getirilmesi maliyetli veriler (örneğin ürün kategorileri veya döviz kurları) için uygulama içi cache yerine Redis gibi dağıtık çözümler kullanılmalıdır. Spring Cache soyutlaması sayesinde @Cacheable anotasyonu ile servis katmanınızı kolayca hızlandırabilirsiniz.

Dikkat Edilmesi Gerekenler: - TTL (Time To Live): Verinin ne kadar süre cache'te kalacağını iş mantığınıza göre belirleyin. - Cache Eviction: Veri güncellendiğinde cache'in temizlendiğinden emin olun (@CacheEvict).

4. Gözlemlenebilirlik (Observability)

Neyi ölçemezseniz onu optimize edemezsiniz. Spring Boot Actuator, Micrometer ve Prometheus üçlüsü ile uygulamanızın anlık CPU, bellek ve HTTP istek sürelerini takip edin. Grafana üzerinde oluşturacağınız dashboard'lar, darboğazları kullanıcılarınız fark etmeden önce sizin görmenizi sağlar.

Sonuç

Performans optimizasyonu bir varış noktası değil, sürekli devam eden bir yolculuktur. Uygulamanız büyüdükçe yük testleri (JMeter, K6) yaparak zayıf halkaları tespit etmeli ve yukarıdaki teknikleri uygulamalısınız.

Ölçüm Olmadan Optimizasyon Yapmayın

Bir uç noktanın yavaş olduğunu söylemeden önce ölçülebilir bir hedef belirleyin. Örneğin ürün arama servisi için normal yükte p95 yanıt süresini 250 ms, hata oranını yüzde 0,5 ve veritabanı bağlantı bekleme süresini 20 ms altında tutmak bir hizmet seviyesi hedefi olabilir. Ortalama süre tek başına yanıltıcıdır; yüz isteğin doksanı hızlı, onu çok yavaşsa ortalama kabul edilebilir görünürken gerçek kullanıcıların bir bölümü sürekli bekler.

Testi üretim verisine benzeyen veri hacmiyle gerçekleştirin. On bin satırla hızlı çalışan bir sorgu, on milyon satırda farklı yürütme planına geçebilir. k6 veya Gatling senaryosunda yalnızca sabit istek sayısı göndermek yerine oturum açma, listeleme, filtreleme ve güncelleme gibi gerçek kullanıcı akışlarını oranlarıyla modelleyin. Test sırasında uygulama CPU'su, heap kullanımı, garbage collection duraklamaları, HikariCP active/pending bağlantıları ve veritabanı sorgu sürelerini aynı zaman çizelgesinde izleyin.

Darboğazı Katman Katman Ayırma

Performans problemi görüldüğünde ilk refleks cache eklemek olmamalıdır. Aşağıdaki sıra sorunun kaynağını daha az yan etkiyle bulmayı sağlar:

  • İstek süresini controller, servis, dış servis ve veritabanı segmentlerine ayırın.
  • Yavaş sorgular için gerçek parametrelerle EXPLAIN (ANALYZE, BUFFERS) çıktısı alın.
  • Aynı verinin istek içinde tekrar tekrar okunup okunmadığını kontrol edin.
  • Thread pool ve bağlantı havuzunda bekleyen iş sayısını izleyin.
  • Dış servis çağrılarına bağlantı ve okuma timeout'u koyun; sınırsız retry kullanmayın.

Örneğin p95 süresi 900 ms olan bir isteğin 720 ms'si veritabanında geçiyorsa JVM ayarıyla uğraşmak sonuç vermez. Buna karşılık sorgu 40 ms sürüyor fakat istek 700 ms kuyrukta bekliyorsa havuz boyutları, bloklayan işler veya aşağı akış bağımlılıkları incelenmelidir.

Cache Tasarımında Tutarlılık Bedeli

@Cacheable eklemek okuma süresini düşürebilir ancak veri güncelliği sorununu da beraberinde getirir. Cache anahtarına tenant, dil ve yetki kapsamı gibi sonucu değiştiren bütün bileşenleri dahil edin. Aksi halde bir müşterinin verisi başka müşteriye gösterilebilir. TTL değerini rastgele seçmek yerine verinin kabul edilebilir bayatlık süresine göre belirleyin. Ürün stok bilgisi ile ülke listesi aynı TTL'e sahip olmamalıdır.

Cache stampede riskinde, süresi dolan popüler bir anahtar için yüzlerce istek aynı anda veritabanına gidebilir. Anahtar bazlı kilit, erken yenileme veya kısa süreli jitter bu yükü dağıtır. Cache hata verdiğinde uygulamanın kontrollü biçimde ana kaynağa dönmesi gerekir; Redis kesintisinin tüm API'yi durdurması iyi bir tasarım değildir.

Üretime Alma Kontrol Listesi

  • Değişiklik öncesi ve sonrası aynı yük senaryosunu çalıştırın.
  • p50, p95 ve p99 değerlerini ayrı karşılaştırın.
  • Sorgu sayısı, dönen satır sayısı ve taşınan payload boyutunu kaydedin.
  • Timeout, retry ve circuit breaker sınırlarını belgelerin.
  • Canary yayında hata oranını ve kaynak tüketimini eski sürümle karşılaştırın.
  • Kazanım yoksa karmaşıklık ekleyen optimizasyonu geri alın.

En iyi performans çalışması tek bir sihirli ayar değil; hipotez, ölçüm, küçük değişiklik ve yeniden ölçüm döngüsüdür. Böyle ilerlediğinizde hız kazanırken veri tutarlılığı ve sistem dayanıklılığını kaybetmezsiniz.