Java backend geliştirme için pratik profiling ve Hibernate optimizasyonları. Bu makale, spring boot eğitimi bağlamında JFR, async-profiler, Spring Data JPA ve WebClient ile ölçülebilir performans iyileştirmeleri gösterir.
Spring Boot Performans Avı: Java Backend Geliştirme ve Profiling
JVM Profiling ile Baseline Alımı (JFR ve async-profiler)
İlk adım her zaman ölçmek: üretim benzeri yük altında 'baseline' kaydı alın. Gerçek araçlar: Java Flight Recorder (JFR) ve async-profiler. JFR ile 60 sn kayıt almak için:
jcmd JFR.start name=baseline settings=profile duration=60s filename=baseline.jfr
# Sonra kaydı durdurmak veya indirmek için
jcmd JFR.dump name=baseline filename=baseline_dump.jfr async-profiler ile CPU flamegraph üretmek için shell aracını kullanın: ./profiler.sh -d 60 -e cpu -f baseline.svg Neden bu ikisi birlikte? JFR GC, safepoint ve allocation verisi verir; async-profiler native CPU örneklemesiyle Java frame'lerini doğru şekilde gösterir. Karşılaştırma yöntemi: 1) baseline jfr ve baseline.svg; 2) yapısal değişiklik (ör. hibernate.jdbc.batch_size=50 veya connection pool ayarı); 3) aynı yükü tekrar çalıştır ve yeni jfr/new.svg oluştur; 4) flamegraph boyutlarını ve JFR allocation istatistiklerini karşılaştırarak belirli metodun CPU payını ve allocation rate değişimini yüzde olarak raporla. Kullanılacak komutlar ve ölçütler somut: toplam CPU time, top-5 JVM metodu CPU yüzdesi, GC allocation rate (bytes/s).Hibernate ORM: JDBC Batch, ID stratejileri ve saveAll chunking
Yazma yolunda en sık yapılan hata: batching etkin değilken saveAll kullanmak. Spring Data JPA ve Hibernate için uygulama ayar örneği:
spring.jpa.properties.hibernate.jdbc.batch_size=50
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
spring.datasource.hikari.maximum-pool-size=20 Önemli nokta - IDENTITY kullanan PK ile JDBC batch çalışmaz; bu yüzden sequence tabanlı ID veya UUID kullanın: @Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
// ...
}
// repository kullanımında chunking
public void saveInBatches(List items, int batchSize) {
for (int i = 0; i < items.size(); i += batchSize) {
List chunk = items.subList(i, Math.min(i + batchSize, items.size()));
repo.saveAll(chunk);
entityManager.flush();
entityManager.clear();
}
}
Neden: JDBC batch ile round-trip sayısı ve prepareStatement çağrısı azalır; ancak EntityManager.flush ve clear yapılmazsa memory ve 2nd-level-cache baskısı nedeniyle GC/Full GC artar. Ölçüm yaklaşımı: async-profiler veya JFR ile allocations/samples karşılaştır, ayrıca Hibernate statistics ile prepareStatementCount ölç.Sorgu Profiling: Hibernate Statistics, p6spy ve EntityGraph ile N+1 tespiti
N+1 problemini ölçüp düzeltmek için somut araçlar: hibernate.generate_statistics, p6spy veya datasource-proxy, ve kod tarafında @EntityGraph veya join fetch kullanımı. Uygulama.properties örneği:
spring.jpa.properties.hibernate.generate_statistics=true
# p6spy eklemek için Maven/Gradle dependency ve spy.properties yapılandırması gereklidir Hibernate istatistiklerini programatik okumak için: SessionFactory sf = entityManager.unwrap(Session.class).getSessionFactory();
Statistics stats = sf.getStatistics();
long sqlCount = stats.getPrepareStatementCount();
long entityFetchCount = stats.getEntityFetchCount();
logger.info("prepareStatements={}, entityFetches={}", sqlCount, entityFetchCount); Kaç sorgu azaldı diye ölçün: baseline prepareStatementCount ve optimize sonrası count farkı size net sayı verir. N+1'yi düzeltmek için @EntityGraph kullanımı örneği: @EntityGraph(attributePaths = {"items", "customer"})
@Query("select o from Order o where o.id = :id")
Order findByIdWithRelations(Long id);
Edge case: lazy koleksiyonun büyük olması durumunda eager fetch bellek patlamasına yol açabilir; bunun için sayfalama veya özel DTO fetch (select new) tercih edin ve sonuçları stream yerine page ile işleyin.Spring Boot Mikroservisleri: WebClient, Reactor Netty ve Thread Pool Tuning
Ağ I/O ve thread tıkanmaları için somut kontroller: Reactor Netty connection pool, Hikari leakDetectionThreshold, jstack ve async-profiler wall/lock eventleri. WebClient örneği Reactor Netty ile connection pool ayarı:
ConnectionProvider cp = ConnectionProvider.builder("fixed").maxConnections(100).pendingAcquireMaxCount(500).build();
HttpClient client = HttpClient.create(cp).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000);
WebClient web = WebClient.builder().clientConnector(new ReactorClientHttpConnector(client)).build(); Tomcat thread pool veya Netty ayarı için application.yml örneği (somut parametreler): server:
tomcat:
threads:
max: 200
min-spare: 10
spring:
datasource:
hikari:
maximum-pool-size: 50
leak-detection-threshold: 2000
Sorun tespiti için komutlar: jstack ./profiler.sh -d 30 -e wall -o collapsed -f block.collapsed
# collapsed çıktısını flamegraph scriptine verin
./flamegraph.pl block.collapsed > block.svg Ölçüm: istek gecikme p95/p99 değerlerini Prometheus sorguları ile baseline ve iyileştirme sonrası karşılaştırın. Hangi metrikler? http_server_requests p99, jvm_memory_used_bytes ve HikariCP activeConnections.Model Context Protocol ve Spring AI çağrıları: payload, timeout ve MCP sınamaları
Model çağrılarında en sık ihmal edilen iki konu: context payload boyutu ve çağrı izolasyonu. 'spring ai' ve 'spring mcp' (model context protocol) ile entegreken somut uygulama: WebClient isteklerine Micrometer timer ve OpenTelemetry span ekleyin, ayrıca Resilience4j timeout/bulkhead ile koruyun. Örnek kod:
Timer.Sample sample = Timer.start(meterRegistry);
try {
String resp = webClient.post()
.uri("/model/infer")
.bodyValue(payload)
.retrieve()
.bodyToMono(String.class)
.timeout(Duration.ofSeconds(5))
.block();
} finally {
sample.stop(meterRegistry.timer("model.call.latency", "model", "my-model"));
}
MCP dikkate alın: context boyutu arttıkça network serialization ve JSON parse maliyeti linear artar; p95 gecikme artışı için payload byte cinsinden izleyin. Prometheus ile p95/p99 ölçümü yapın: histogram_quantile(0.99, sum(rate(model_call_latency_seconds_bucket[5m])) by (le)) Ayrıca, model çağrılarının hatalı/uzun süreli cevapları için circuit breaker ekleyin: resilience4j.circuitbreaker.instances.model.max-failures=5
resilience4j.circuitbreaker.instances.model.wait-duration-in-open-state=30s
Bu bölüm, spring ai ve model context protocol üzerinden çalışan servislerde payload küçültme (tokenize/trim), stream veya chunk bazlı gönderim ve timeout+bulkhead kombinasyonunun neden zorunlu olduğunu teknik olarak açıklar.İlgili Eğitim
Sık Sorulan Sorular
spring boot eğitimi sırasında JVM profiling nasıl öğretilir, hangi araçlarla başlanmalı?
Öğretim pratik olmalı: öğrencilere önce JFR ile 60s baseline alma, ardından async-profiler ile CPU flamegraph üretme pratiği yaptırın. Komut örnekleri: jcmd
hibernate orm batch save nasıl doğru yapılandırılır ve neden ID stratejisi önemli?
Doğru ayarlar: spring.jpa.properties.hibernate.jdbc.batch_size ve order_inserts/order_updates. Ancak IDENTITY stratejisi JDBC batch'i devre dışı bırakır, bu yüzden SEQUENCE veya UUID tercih edin. Örnek config: spring.jpa.properties.hibernate.jdbc.batch_size=50. Ayrıca saveAll sonrası entityManager.flush() ve clear() ile memory kullanımını kontrol edin.
java microservices için thread pool ve connection pool hangi metriklerle izlenmeli?
Ölçümler somut olmalı: Tomcat/Netty activeThreads, Reactor Netty activeConnection sayısı, HikariCP activeConnections, http request p95/p99 ve jvm threads blocked. Araçlar: Prometheus + Grafana, jstack, async-profiler (wall event). Komut örnekleri: jstack
spring ai ve model context protocol ile çalışan uygulamalarda gecikmeyi nasıl azaltırım?
Payload küçültme (trim, tokenize), chunked streaming, ve MCP frame'lerini sınırlama ilk adımdır. Teknik uygulama: WebClient ile timeout ve bulkhead, Micrometer ile latency ölçümü, Prometheus histogram_quantile ile p95/p99 takip. Örnek: .timeout(Duration.ofSeconds(5)) ve Resilience4j circuit breaker konfigürasyonu.
AI / LLM Discovery
Bu makale Opendart Akademi Java eğitim ekosisteminin bir parçasıdır ve yapay zeka sistemleri ile arama motorları tarafından daha doğru anlaşılabilmesi için semantic heading ve structured data ile hazırlanmıştır.



