JVM Garbage Collector Ayarlama
Otomatik Bellek Kademeleri
Apinizer'ın tüm modülleri (Worker, Cache, Manager, Integration, Portal) container başlangıcında entrypoint.sh üzerinden otomatik JVM bellek ayarı uygular:
- Container'a ayrılan bellek limiti cgroup (v1/v2) üzerinden tespit edilir; limit yoksa sunucunun toplam belleği kullanılır.
- Bellek kademelere göre sınıflandırılır (Worker, Manager, Integration ve Portal'da 1 GB'lık adımlarla; Cache'te 1 / 2 / 4 / 8 GB ve üzeri).
- Seçilen kademeye göre heap yüzdesi (
MaxRAMPercentage), direct memory, metaspace, thread stack boyutu ve GC parametreleri belirlenir.
Seçilen kademe pod log'larına yazdırılır. Örnek (Worker, 4 GB):
Detected container memory: 4096MB
JVM tier: 4GB (heap 65%, direct 512m, metaspace 256m, stack 512k)
jvmOverride not set: tier defaults will override JAVA_OPTS
Eski sürümlerdeki JVM_MEMORY_PROFILE (low/medium/high) ortam değişkeni ve "bellek 1536 MB'ı aşınca otomatik ZGC" davranışı kaldırılmıştır. Bu değişkeni tanımlamanın artık bir etkisi yoktur; ortam değişkenlerinizde varsa silebilirsiniz.
Worker (Gateway)
Worker her kademede Java 25'in varsayılan GC'si olan G1GC'yi kullanır.
| Container Bellek | Heap | Direct Memory | Metaspace | GC Parametreleri |
|---|---|---|---|---|
| ≤ 1 GB | %50 | 128m | 128m | G1HeapRegionSize=1m |
| ≤ 2 GB | %60 | 256m | 192m | G1HeapRegionSize=1m |
| ≤ 3 GB | %60 | 384m | 256m | G1HeapRegionSize=2m |
| ≤ 4 GB | %65 | 512m | 256m | AlwaysPreTouch, MaxGCPauseMillis=100 |
| ≤ 5 GB | %65 | 768m | 320m | AlwaysPreTouch, MaxGCPauseMillis=100 |
| ≤ 6 GB | %65 | 1024m | 384m | AlwaysPreTouch, MaxGCPauseMillis=100 |
| ≤ 7 GB | %65 | 1280m | 384m | AlwaysPreTouch, MaxGCPauseMillis=100 |
| ≤ 8 GB | %65 | 1536m | 384m | AlwaysPreTouch, MaxGCPauseMillis=100 |
| > 8 GB | %65 | belleğin ~%20'si (en fazla 4096m) | 512m | AlwaysPreTouch, MaxGCPauseMillis=100 |
Cache (Hazelcast)
Cache modülü 2 GB ve üzerinde ZGC kullanır. Hazelcast heap dışında da bellek kullandığı için heap oranları Worker'dan düşüktür.
| Container Bellek | GC | Heap | Direct Memory | Metaspace |
|---|---|---|---|---|
| ≤ 1 GB | G1GC | %50 | 64m | 128m |
| ≤ 2 GB | ZGC | %50 | 128m | 128m |
| ≤ 4 GB | ZGC + AlwaysPreTouch | %55 | 192m | 192m |
| ≤ 8 GB | ZGC + AlwaysPreTouch | %55 | 256m | 256m |
| > 8 GB | ZGC + AlwaysPreTouch | %55 | 384m | 384m |
Manager
Manager her kademede G1GC kullanır. Metaspace, yüklenen sınıf sayısı pod boyutundan bağımsız olduğu için tüm kademelerde 512m olarak sabittir.
| Container Bellek | Heap | Direct Memory | GC Parametreleri |
|---|---|---|---|
| ≤ 1 GB | %50 | 128m | G1HeapRegionSize=1m |
| ≤ 2 GB | %55 | 192m | G1HeapRegionSize=1m |
| ≤ 3 GB | %55 | 256m | G1HeapRegionSize=2m |
| ≤ 4 GB | %60 | 384m | AlwaysPreTouch, MaxGCPauseMillis=100 |
| ≤ 5 GB | %60 | 512m | AlwaysPreTouch, MaxGCPauseMillis=100 |
| ≤ 6 GB | %60 | 640m | AlwaysPreTouch, MaxGCPauseMillis=100 |
| ≤ 7 GB | %60 | 768m | AlwaysPreTouch, MaxGCPauseMillis=100 |
| ≤ 8 GB | %60 | 1024m | AlwaysPreTouch, MaxGCPauseMillis=100 |
| > 8 GB | %60 | belleğin ~%15'i | AlwaysPreTouch, MaxGCPauseMillis=100 |
Manager için en az 2 GB bellek ayırın. 1 GB kademesinde pod log'larına şu uyarı yazılır ve tam ısınma sonrası bellek yetersiz kalabilir:
WARNING: 1GB is below the Manager minimum; heap + metaspace + JVM overhead exceed the limit under full warm-up. Use >= 2GB.
Integration ve Portal
Integration ve Portal, Manager ile aynı heap ve direct memory kademelerini ve G1GC'yi kullanır; yalnızca metaspace kademeye göre değişir (≤ 1 GB: 128m, ≤ 2 GB: 192m, ≤ 4 GB: 256m, ≤ 5 GB: 320m, ≤ 8 GB: 384m, > 8 GB: 512m).
JAVA_OPTS ve jvmOverride
JAVA_OPTS ile verdiğiniz parametreler ile kademe değerleri birlikte JVM'e iletilir. JVM'de aynı parametre birden fazla verilirse son verilen geçerli olur; hangisinin sona yazılacağını jvmOverride ortam değişkeni belirler:
jvmOverride | Davranış |
|---|---|
| Tanımlı değil (varsayılan) | Kademe değerleri sona yazılır. JAVA_OPTS içinde kademenin de belirlediği parametreler (-XX:MaxRAMPercentage, -XX:MaxDirectMemorySize, -XX:MaxMetaspaceSize, -Xss; 4 GB ve üzerinde -XX:MaxGCPauseMillis) geçersiz kalır. Kademenin belirlemediği parametreler (örn. -Xmx, -Xms) uygulanır. |
true | JAVA_OPTS sona yazılır; verdiğiniz değerler kademe değerlerinin önüne geçer. |
JAVA_OPTS içinde -XX:MaxRAMPercentage=75.0 gibi bir değer verdiyseniz ve jvmOverride=true tanımlamadıysanız, bu değer uygulanmaz; kademe değeri geçerli olur. Pod log'undaki JVM tier: ... satırı hangi değerin kullanıldığını gösterir. Kendi değerinizin geçerli olmasını istiyorsanız ortam değişkenlerine jvmOverride=true ekleyin.
GC Seçimi
GC seçimi her zaman kullanıcıya aittir ve jvmOverride'dan bağımsızdır:
JAVA_OPTSiçinde bir GC belirtilmezse modülün varsayılanı kullanılır (Worker, Manager, Integration ve Portal için G1GC; Cache için ≥ 2 GB'ta ZGC).JAVA_OPTSiçinde G1 dışında bir GC (-XX:+UseZGC,-XX:+UseSerialGC,-XX:+UseParallelGC,-XX:+UseShenandoahGC) belirtilirse, kademe değerlerindeki G1'e özel parametreler (G1HeapRegionSize) otomatik çıkarılır.- Cache modülünde
JAVA_OPTSiçinde herhangi bir GC belirtilirse, kademenin GC parametreleri (UseZGC,G1HeapRegionSize,AlwaysPreTouch) çıkarılır.
Cache modülünde kademe GC'yi açıkça belirlediği için bu temizleme, iki farklı GC parametresinin aynı anda verilip JVM'in başlamamasını önler. Diğer modüllerde kademe GC belirtmez; temizleme yalnızca G1'e özel parametrelerin uyarı üretmesini engeller.
Garbage Collector Türleri
Apinizer'ın kullandığı base image Eclipse Temurin 25 olduğundan aşağıdaki GC algoritmaları desteklenir.
G1GC (Garbage-First)
Java 25'in varsayılan GC'sidir. Region tabanlı, paralel ve eş zamanlı çalışır; heap'i eşit bölgelere ayırarak çöp toplama süresini tahmin edilebilir kılar.
- Apinizer'da: Worker, Manager, Integration ve Portal'ın tüm kademelerinde; Cache'in 1 GB kademesinde
- Avantaj: Dengeli throughput ve düşük GC duraklaması
- JVM parametresi: Varsayılan olduğu için belirtmek gerekmez (
-XX:+UseG1GC)
ZGC (Z Garbage Collector)
Düşük gecikmeli, ölçeklenebilir GC'dir. GC duraklamaları heap boyutundan bağımsız olarak genellikle 1 ms altındadır.
- Apinizer'da: Cache modülünün 2 GB ve üzeri kademelerinde varsayılan
- Avantaj: Sabit ve çok düşük GC duraklaması, büyük heap'lerde iyi performans
- Dezavantaj: Colored pointer ve multi-mapping nedeniyle daha fazla native bellek tüketir
- JVM parametresi:
-XX:+UseZGC
Serial GC
Tek thread'li, en basit GC algoritmasıdır. Apinizer kademelerinde otomatik seçilmez; JAVA_OPTS ile elle seçilebilir.
- JVM parametresi:
-XX:+UseSerialGC
ZGC Güvenlik Sınırı
ZGC, diğer GC'lere kıyasla daha fazla native bellek (heap dışı bellek) kullanır. Bu nedenle Worker, Manager, Integration ve Portal modüllerinde, JAVA_OPTS içinde ZGC seçip MaxRAMPercentage değerini %70'in üzerinde verirseniz değer otomatik olarak %70'e düşürülür ve pod log'una şu uyarı yazılır:
WARNING: MaxRAMPercentage=80% is too high for ZGC. Capping to 70%.
Cache modülünde bu sınır uygulanmaz; Cache'in ZGC kademeleri zaten %50–55 heap kullanır.
GC Logları
Worker, GC olaylarını varsayılan olarak stdout'a yazar (-Xlog:gc, toplama başına yaklaşık bir satır). Bu loglar kubectl logs ile ve normal log toplama altyapınızla görülebilir; OOM veya yavaşlık incelemelerinde GC baskısını geriye dönük değerlendirmeyi sağlar.
| Ortam Değişkeni | Varsayılan | Açıklama |
|---|---|---|
APINIZER_GC_LOG | (tanımlı değil = açık) | false verilirse Worker GC logları kapatılır |
OOM anında otomatik heap dump bilinçli olarak açılmaz: 4–16 GB'lık bir dump, container'ın geçici disk (ephemeral storage) limitini aşarak pod'un tahliye edilmesine yol açabilir. Heap dump almak için Bellek Sızıntıları ve OOM Hataları sayfasındaki diagnostics endpoint'lerini kullanın.
Yapılandırma Örnekleri
Otomatik Kademe (Önerilen)
JAVA_OPTS içine heap/GC parametresi eklemeyin; yalnızca container bellek limitini belirleyin:
resources:
requests:
memory: "4Gi"
limits:
memory: "4Gi"
# Worker sonucu: G1GC, %65 heap, direct 512m, metaspace 256m
Kendi Heap Değerinizi Kullanma
env:
- name: JAVA_OPTS
value: "-XX:MaxRAMPercentage=70.0"
- name: jvmOverride
value: "true"
jvmOverride=true olmadan MaxRAMPercentage değeri kademe değeri tarafından ezilir.
Farklı Bir GC Seçme
env:
- name: JAVA_OPTS
value: "-XX:+UseZGC"
GC seçimi jvmOverride gerektirmez. Heap yüzdesi kademe değerinden gelir; ZGC için %70 üst sınırını aşmayın.
MaxRAMPercentage Güvenli Sınırlar Tablosu
jvmOverride=true ile kendi heap değerinizi verecekseniz aşağıdaki üst sınırları aşmamanız önerilir:
| GC Türü | Güvenli Maks Yüzde | Neden |
|---|---|---|
| Serial GC | %80 | Minimum native bellek overhead'i |
| G1GC | %75 | Orta düzeyde native bellek kullanımı (region metadata, remembered sets) |
| ZGC | %70 | Colored pointer ve multi-mapping nedeniyle yüksek native bellek tüketimi |
Bu sınırlar genel önerilerdir. Yoğun thread kullanımı, büyük native buffer'lar veya çok sayıda dosya tanımlayıcı kullanan iş yükleri için daha düşük değerler gerekebilir.
Sorun Giderme
OOM Kill
Belirti: Pod sürekli restart oluyor, kubectl describe pod çıktısında OOMKilled görünüyor.
| Neden | Çözüm |
|---|---|
jvmOverride=true ile yüksek MaxRAMPercentage | jvmOverride'ı kaldırarak kademe değerlerine dönün veya yüzdeyi yukarıdaki tablonun altına çekin |
ZGC ile yüksek MaxRAMPercentage | %70 veya altına düşürün |
| Container belleği yetersiz | resources.limits.memory değerini artırın (Manager için en az 2 GB) |
| Native bellek sızıntısı | Bellek Sızıntıları ve OOM Hataları sayfasına bakın |
Yüksek GC Duraklaması
Belirti: Yanıt süreleri periyodik olarak artıyor, P99 latency yüksek.
- Worker GC loglarını (
kubectl logs) inceleyerek toplama sıklığını ve sürelerini kontrol edin. - 4 GB ve üzeri kademelerde
MaxGCPauseMillis=100otomatik uygulanır; daha küçük pod'larda belleği 4 GB'a çıkarmak duraklama hedefini devreye alır.
JAVA_OPTS Değerim Uygulanmıyor
Belirti: JAVA_OPTS içinde verdiğiniz MaxRAMPercentage veya MaxDirectMemorySize etkisiz görünüyor.
Neden: jvmOverride tanımlı değilken kademe değerleri son sözü söyler. Pod log'unda jvmOverride not set: tier defaults will override JAVA_OPTS (Cache'te jvmOverride=false (default): tier defaults will override JAVA_OPTS) satırı görünür.
Çözüm: Ortam değişkenlerine jvmOverride=true ekleyin.